带固定列支持横向滑动的ListView

说明:

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

动画效果:


布局说明:


对应代码目录结构:

主要类以及方法说明:

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时才认为是滑动事件 参考www.cnblogs.com/ut2016-progam/p/5341774.html
            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;
}

源码下载地址:

用到的知识点以及相关推荐:

1、滑动速度跟踪类VelocityTracker介绍:

http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2012/1117/574.html

2、fling参数

http://tieba.baidu.com/p/4190326255

3、Scroller源码分析参考

http://blog.csdn.net/yanbober/article/details/49904715

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


  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值