首页 > 系统 > Android > 正文

Android中实现水平滑动(横向滑动)ListView示例

2020-04-11 11:31:45
字体:
来源:转载
供稿:网友

水平的ListView-HorizontalListView的使用

Android中ListView默认的是竖直方向的滑动,由于项目的需求,需要ListView是水平滑动的。有很多的方式可以实现,但是比较好的一种方式就是自己封装一个控件,使用方式和ListView的使用方式是一样的。需要完善的地方:获取到的图片大小没有处理。在界面上展示的是图片的原大小。为了更好的展示效果,应该压缩成统一的尺寸。

HorizontalListView.java 代码如下:

/** * 横向的ListView *  * * @author scd *  */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());    }  };}

适配器 HorizontalListViewAdapter .java如下:

public class HorizontalListViewAdapter extends BaseAdapter {  /** 上下文 */  private Context mContext;  /** 图像数据源 */  private ArrayList<Map<String, Integer>> mImageList;  /** 数据源 */  private ArrayList<Map<String, Integer>> mTextList;  /** Image */  private static String IMAGE = "ic_";  private Map<String, Integer> mMap = null;  /** 构造方法 */  public HorizontalListViewAdapter(Context context) {    this.mContext = context;    initData();  }  /** 初始化数据 */  public void initData() {    mImageList = new ArrayList<Map<String, Integer>>();    /*     * 反射技术     */    Class<?> imageClzz = R.drawable.class;    R.drawable instance = new R.drawable();    // 取得drawable类中所有的字段    Field[] fields = imageClzz.getDeclaredFields();    for (Field field : fields) {      // 获得字段的名字      String name = field.getName();      if (name != null && name.startsWith(IMAGE)) {        try {          mMap = new HashMap<String, Integer>();          mMap.put(IMAGE, (Integer) field.get(instance));          mImageList.add(mMap);        } catch (IllegalAccessException e) {          e.printStackTrace();        }      }    }  }  @Override  public int getCount() {    return mImageList.size();  }  @Override  public Map<String, Integer> getItem(int position) {    return mImageList == null ? null : mImageList.get(position);  }  @Override  public long getItemId(int position) {    return position;  }  @Override  public View getView(int position, View convertView, ViewGroup parent) {    ViewHolder holder;    if (convertView == null) {      holder = new ViewHolder();      convertView = LayoutInflater.from(mContext).inflate(          R.layout.horizontal_list_item, null);      holder.mImage = (ImageView) convertView          .findViewById(R.id.iv_list_item);      holder.mTitle = (TextView) convertView          .findViewById(R.id.tv_list_item);      convertView.setTag(holder);    } else {      holder = (ViewHolder) convertView.getTag();    }    if (position == mSelectIndex) {      convertView.setSelected(true);    } else {      convertView.setSelected(false);    }    holder.mImage.setImageResource(getItem(position).get(IMAGE));    return convertView;  }  private class ViewHolder {    /** 图像 */    private ImageView mImage;  }}

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表