说明:


说明:可横向滑动的ListView(包含固定列和滚动列),本示例重点在列表可横向滚动时涉及的手势以及滚动距离计算,不过只是Demo给出思路,细节没有处理,也没有进行完善。


动画效果:

Android ListView 横排 示例 listview横向滑动_android

布局说明:


Android ListView 横排 示例 listview横向滑动_手势滑动_02


对应代码目录结构:




Android ListView 横排 示例 listview横向滑动_android_03


主要类以及方法说明:

1、DragableListViewItem.java类中动态创建每行Item的布局方法


/**
 * 动态创建每行Item的布局
 * @param viewGroup :每行item的父容器(有固定列和非固定列2种父容器)
 * @param index:列数索引
 * @param value :文本值
 */
public void setValue(ViewGroup viewGroup, int index, String value) {
    TextView t;
    LayoutParams l;
    if (viewGroup.getChildCount() > index) {
        t = (TextView) viewGroup.getChildAt(index);
    } else {
        t = (TextView) inflater.inflate(R.layout.column_dragable_list_item_cell, null);
        if (viewGroup == contentColumn) {
            t.setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL);
            l = new LayoutParams(columnWidth, height);
        } else {
            t.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
            l = new LayoutParams(columnWidth, height);
        }
        viewGroup.addView(t, l);
    }
    t.setText(value);
}

2、listView的onTouch事件 处理横向滑动。关键点已经注释,该onTouchEvent方法中涉及到的其他一些方法,比如getMoveItemScrollX等也已在相应方法中做了注释。


/*
* 横向滑动的核心方法
* */
public boolean onTouchEvent(MotionEvent ev) {
    if (mVelocityTracker == null)
        mVelocityTracker = VelocityTracker.obtain();//手势滑动事件跟踪器
    mVelocityTracker.addMovement(ev);
    int action = ev.getAction();
    float x = ev.getX();
    float y = ev.getY();
    switch (action) {
        case MotionEvent.ACTION_DOWN:
            if (!mScroller.isFinished()) {
                mScroller.abortAnimation();
            }
            mIsDragging = false;//是否处于滑动状态,置为false
            mLastMotionX = x;
            mLastMotionDownX = x;
            mLastMotionDownY = y;
            break;
        case MotionEvent.ACTION_MOVE:
            int xDiff = (int) Math.abs(x - this.mLastMotionDownX);//
            int yDiff = (int) Math.abs(y - this.mLastMotionDownY);
            //滑动距离大于mTouchSlop时才认为是滑动事件 
            if ((xDiff > mTouchSlop) && (xDiff > yDiff * 2))
                this.mIsDragging = true;
            if (mIsDragging) {
                if (x > mLastMotionX) { //向右滑动
                    mDirection = DIRECTION_RIGHT;
                } else {
                    mDirection = DIRECTION_LEFT;
                }
                int deltaX = (int) (mLastMotionX - x);//滑动的距离
                mLastMotionX = x;//别忘记赋值
                if (isCanScrollAble()) {
                    if (deltaX < 0) {//向右滑动
                        if (getMoveItemScrollX() > 0) {
                            //Math.max(-getMoveItemScrollX(), deltaX)
                            //向右滑动时,手指滑动过的距离大于已经左滑的部分时,以左滑宽度为准,
                            //否则,以手势滑动距离为的实际的偏移值。
                            itemScrollBy(Math.max(-getMoveItemScrollX(), deltaX), 0);
                        }
                    } else if (deltaX > 0) { //向左滑动
                        int availableToScroll = getAvailableToScroll();
                        if (availableToScroll > 0) {
                            //Math.min(availableToScroll, deltaX)
                            //本次滑动实际的偏移距离:
                            //手势滑动距离> 可向左滑动的距离时,以可向左滑动的距离为准
                            //手势滑动距离< 可向左滑动的距离,以手势滑动距离为准
                            itemScrollBy(Math.min(availableToScroll, deltaX), 0);
                        }
                    }
                }
            }
            break;
        case MotionEvent.ACTION_UP:
            if (mIsDragging) {
                VelocityTracker velocity = mVelocityTracker;
                velocity.computeCurrentVelocity(1000);//1000毫秒移动了多少距离(速率的单位)
                int velocityX = (int) velocity.getXVelocity();//当前的速度
                //手指松开后定位到哪一列
                if (isCanScrollAble()) {
                    if (Math.abs(velocityX) < SNAP_VELOCITY) {//当前速度小于500px/s时,就定位到具体列
                        snapToColumnDestination();
                    } else {
                        fling(-velocityX);
                    }
                }
                if (velocity != null) {
                    velocity.recycle();
                    velocity = null;
                }
                mIsDragging = false;
                ev.setAction(MotionEvent.ACTION_CANCEL);
                super.onTouchEvent(ev);
            }
            break;
        case MotionEvent.ACTION_CANCEL:
            mIsDragging = false;
            break;
    }
    if (!mIsDragging) {
        super.onTouchEvent(ev);
    }
    //必须返回true,因为onTouchEvent中action_down事件返回true,其他后续的move up等事件才能由该listview处理
    return true;
}