新西兰服务器

Android UI使用HorizontalListView实现水平滑动


Android UI使用HorizontalListView实现水平滑动

发布时间:2020-10-11 07:19:36 来源:脚本之家 阅读:126 作者:过自己想过的生活 栏目:移动开发

今天就介绍一个大神级人物自定义的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就简单说到这里。

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

[微信提示:高防服务器能助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。

[图文来源于网络,不代表本站立场,如有侵权,请联系高防服务器网删除]
[