当前位置: 移动技术网 > IT编程>移动开发>Android > Android UI使用HorizontalListView实现水平滑动

Android UI使用HorizontalListView实现水平滑动

2019年07月30日  | 移动技术网IT编程  | 我要评论

0001901212,天籁水汇,miad640

今天就介绍一个大神级人物自定义的listview实现水平滑动,我知道要实现一个可以水平滑动的方法有很多,但是这个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就简单说到这里。

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

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网