欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android UI使用HorizontalListView实现水平滑动

程序员文章站 2022-06-23 15:02:42
今天就介绍一个大神级人物自定义的listview实现水平滑动,我知道要实现一个可以水平滑动的方法有很多,但是这个horizontallistview用起来是真的很不错!!!...

今天就介绍一个大神级人物自定义的listview实现水平滑动,我知道要实现一个可以水平滑动的方法有很多,但是这个horizontallistview用起来是真的很不错!!!

先看一下效果图:

Android UI使用HorizontalListView实现水平滑动

界面做的不怎么看得上眼,但是基本的动能还是在的,下面给出horizontallistview的代码:

/* 
 * horizontallistview.java v1.5 
 * 
 * 
 * the mit license 
 * copyright (c) 2011 paul soucy (paul@dev-smart.com) 
 * 
 * permission is hereby granted, free of charge, to any person obtaining a copy 
 * of this software and associated documentation files (the "software"), to deal 
 * in the software without restriction, including without limitation the rights 
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
 * copies of the software, and to permit persons to whom the software is 
 * furnished to do so, subject to the following conditions: 
 * 
 * the above copyright notice and this permission notice shall be included in 
 * all copies or substantial portions of the software. 
 * 
 * the software is provided "as is", without warranty of any kind, express or 
 * implied, including but not limited to the warranties of merchantability, 
 * fitness for a particular purpose and noninfringement. in no event shall the 
 * authors or copyright holders be liable for any claim, damages or other 
 * liability, whether in an action of contract, tort or otherwise, arising from, 
 * out of or in connection with the software or the use or other dealings in 
 * the software. 
 * 
 */
import java.util.linkedlist;
import java.util.queue;

import android.content.context;
import android.database.datasetobserver;
import android.graphics.rect;
import android.util.attributeset;
import android.view.gesturedetector;
import android.view.gesturedetector.ongesturelistener;
import android.view.motionevent;
import android.view.view;
import android.widget.adapterview;
import android.widget.listadapter;
import android.widget.scroller;

public class horizontallistview extends adapterview<listadapter> {

 public boolean malwaysoverridetouch = true;
 protected listadapter madapter;
 private int mleftviewindex = -1;
 private int mrightviewindex = 0;
 protected int mcurrentx;
 protected int mnextx;
 private int mmaxx = integer.max_value;
 private int mdisplayoffset = 0;
 protected scroller mscroller;
 private gesturedetector mgesture;
 private queue<view> mremovedviewqueue = new linkedlist<view>();
 private onitemselectedlistener monitemselected;
 private onitemclicklistener monitemclicked;
 private onitemlongclicklistener monitemlongclicked;
 private boolean mdatachanged = false;


 public horizontallistview(context context, attributeset attrs) {
  super(context, attrs);
  initview();
 }

 private synchronized void initview() {
  mleftviewindex = -1;
  mrightviewindex = 0;
  mdisplayoffset = 0;
  mcurrentx = 0;
  mnextx = 0;
  mmaxx = integer.max_value;
  mscroller = new scroller(getcontext());
  mgesture = new gesturedetector(getcontext(), mongesture);
 }

 @override
 public void setonitemselectedlistener(adapterview.onitemselectedlistener listener) {
  monitemselected = listener;
 }

 @override
 public void setonitemclicklistener(adapterview.onitemclicklistener listener){
  monitemclicked = listener;
 }

 @override
 public void setonitemlongclicklistener(adapterview.onitemlongclicklistener listener) {
  monitemlongclicked = listener;
 }

 private datasetobserver mdataobserver = new datasetobserver() {

  @override
  public void onchanged() {
   synchronized(horizontallistview.this){
    mdatachanged = true;
   }
   invalidate();
   requestlayout();
  }

  @override
  public void oninvalidated() {
   reset();
   invalidate();
   requestlayout();
  }

 };

 @override
 public listadapter getadapter() {
  return madapter;
 }

 @override
 public view getselectedview() {
  //todo: implement
  return null;
 }

 @override
 public void setadapter(listadapter adapter) {
  if(madapter != null) {
   madapter.unregisterdatasetobserver(mdataobserver);
  }
  madapter = adapter;
  madapter.registerdatasetobserver(mdataobserver);
  reset();
 }

 private synchronized void reset(){
  initview();
  removeallviewsinlayout();
  requestlayout();
 }

 @override
 public void setselection(int position) {
  //todo: implement
 }

 private void addandmeasurechild(final view child, int viewpos) {
  layoutparams params = child.getlayoutparams();
  if(params == null) {
   params = new layoutparams(layoutparams.fill_parent, layoutparams.fill_parent);
  }

  addviewinlayout(child, viewpos, params, true);
  child.measure(measurespec.makemeasurespec(getwidth(), measurespec.at_most),
    measurespec.makemeasurespec(getheight(), measurespec.at_most));
 }



 @override
 protected synchronized void onlayout(boolean changed, int left, int top, int right, int bottom) {
  super.onlayout(changed, left, top, right, bottom);

  if(madapter == null){
   return;
  }

  if(mdatachanged){
   int oldcurrentx = mcurrentx;
   initview();
   removeallviewsinlayout();
   mnextx = oldcurrentx;
   mdatachanged = false;
  }

  if(mscroller.computescrolloffset()){
   int scrollx = mscroller.getcurrx();
   mnextx = scrollx;
  }

  if(mnextx <= 0){
   mnextx = 0;
   mscroller.forcefinished(true);
  }
  if(mnextx >= mmaxx) {
   mnextx = mmaxx;
   mscroller.forcefinished(true);
  }

  int dx = mcurrentx - mnextx;

  removenonvisibleitems(dx);
  filllist(dx);
  positionitems(dx);

  mcurrentx = mnextx;

  if(!mscroller.isfinished()){
   post(new runnable(){
    @override
    public void run() {
     requestlayout();
    }
   });

  }
 }

 private void filllist(final int dx) {
  int edge = 0;
  view child = getchildat(getchildcount()-1);
  if(child != null) {
   edge = child.getright();
  }
  filllistright(edge, dx);

  edge = 0;
  child = getchildat(0);
  if(child != null) {
   edge = child.getleft();
  }
  filllistleft(edge, dx);


 }

 private void filllistright(int rightedge, final int dx) {
  while(rightedge + dx < getwidth() && mrightviewindex < madapter.getcount()) {

   view child = madapter.getview(mrightviewindex, mremovedviewqueue.poll(), this);
   addandmeasurechild(child, -1);
   rightedge += child.getmeasuredwidth();

   if(mrightviewindex == madapter.getcount()-1) {
    mmaxx = mcurrentx + rightedge - getwidth();
   }

   if (mmaxx < 0) {
    mmaxx = 0;
   }
   mrightviewindex++;
  }

 }

 private void filllistleft(int leftedge, final int dx) {
  while(leftedge + dx > 0 && mleftviewindex >= 0) {
   view child = madapter.getview(mleftviewindex, mremovedviewqueue.poll(), this);
   addandmeasurechild(child, 0);
   leftedge -= child.getmeasuredwidth();
   mleftviewindex--;
   mdisplayoffset -= child.getmeasuredwidth();
  }
 }

 private void removenonvisibleitems(final int dx) {
  view child = getchildat(0);
  while(child != null && child.getright() + dx <= 0) {
   mdisplayoffset += child.getmeasuredwidth();
   mremovedviewqueue.offer(child);
   removeviewinlayout(child);
   mleftviewindex++;
   child = getchildat(0);

  }

  child = getchildat(getchildcount()-1);
  while(child != null && child.getleft() + dx >= getwidth()) {
   mremovedviewqueue.offer(child);
   removeviewinlayout(child);
   mrightviewindex--;
   child = getchildat(getchildcount()-1);
  }
 }

 private void positionitems(final int dx) {
  if(getchildcount() > 0){
   mdisplayoffset += dx;
   int left = mdisplayoffset;
   for(int i=0;i<getchildcount();i++){
    view child = getchildat(i);
    int childwidth = child.getmeasuredwidth();
    child.layout(left, 0, left + childwidth, child.getmeasuredheight());
    left += childwidth + child.getpaddingright();
   }
  }
 }

 public synchronized void scrollto(int x) {
  mscroller.startscroll(mnextx, 0, x - mnextx, 0);
  requestlayout();
 }

 @override
 public boolean dispatchtouchevent(motionevent ev) {
  boolean handled = super.dispatchtouchevent(ev);
  handled |= mgesture.ontouchevent(ev);
  return handled;
 }

 protected boolean onfling(motionevent e1, motionevent e2, float velocityx,
        float velocityy) {
  synchronized(horizontallistview.this){
   mscroller.fling(mnextx, 0, (int)-velocityx, 0, 0, mmaxx, 0, 0);
  }
  requestlayout();

  return true;
 }

 protected boolean ondown(motionevent e) {
  mscroller.forcefinished(true);
  return true;
 }

 private ongesturelistener mongesture = new gesturedetector.simpleongesturelistener() {

  @override
  public boolean ondown(motionevent e) {
   return horizontallistview.this.ondown(e);
  }

  @override
  public boolean onfling(motionevent e1, motionevent e2, float velocityx,
        float velocityy) {
   return horizontallistview.this.onfling(e1, e2, velocityx, velocityy);
  }

  @override
  public boolean onscroll(motionevent e1, motionevent e2,
        float distancex, float distancey) {

   synchronized(horizontallistview.this){
    mnextx += (int)distancex;
   }
   requestlayout();

   return true;
  }

  @override
  public boolean onsingletapconfirmed(motionevent e) {
   for(int i=0;i<getchildcount();i++){
    view child = getchildat(i);
    if (iseventwithinview(e, child)) {
     if(monitemclicked != null){
      monitemclicked.onitemclick(horizontallistview.this, child, mleftviewindex + 1 + i, madapter.getitemid( mleftviewindex + 1 + i ));
     }
     if(monitemselected != null){
      monitemselected.onitemselected(horizontallistview.this, child, mleftviewindex + 1 + i, madapter.getitemid( mleftviewindex + 1 + i ));
     }
     break;
    }

   }
   return true;
  }

  @override
  public void onlongpress(motionevent e) {
   int childcount = getchildcount();
   for (int i = 0; i < childcount; i++) {
    view child = getchildat(i);
    if (iseventwithinview(e, child)) {
     if (monitemlongclicked != null) {
      monitemlongclicked.onitemlongclick(horizontallistview.this, child, mleftviewindex + 1 + i, madapter.getitemid(mleftviewindex + 1 + i));
     }
     break;
    }

   }
  }

  private boolean iseventwithinview(motionevent e, view child) {
   rect viewrect = new rect();
   int[] childposition = new int[2];
   child.getlocationonscreen(childposition);
   int left = childposition[0];
   int right = left + child.getwidth();
   int top = childposition[1];
   int bottom = top + child.getheight();
   viewrect.set(left, top, right, bottom);
   return viewrect.contains((int) e.getrawx(), (int) e.getrawy());
  }
 };
}

在使用的时候直接当做普通的listview使用就可以了!!!(有一点需要注意,也算是这个自定义listview的一点小瑕疵吧,在直接在xml使用该view的时候,如果view的高度设置为wrap_content,实际上回匹配其父布局的高度,所以在使用的时候可以更多情况下需要我们指定list的确切高度)

好了,关于这个mit的horizontallistview就简单说到这里。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。