ListView弹性下拉效果

开源项目地址:https://github.com/chiemy/PullSeparateListView
效果图:
这里写图片描述
用什么实现的?
通过属性动画和事件分发机制实现的。
只分析实现原理和关键代码:
1.自定义一个View继承ListView

public class PullSeparateListView extends ListView 
{

}

2.复写ListView的dispatchTouchEvent方法

    // 核心代码
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        float currentY = ev.getY();
        switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            float downX = ev.getX();
            float downY = ev.getY();
            // 记录按下位置,当isSeparateAll()返回false时,会用到
            originDownPosition = pointToPosition((int) downX, (int) downY);
            downPosition = originDownPosition - getFirstVisiblePosition();
            if (showDownAnim) {
                performDownAnim(downPosition);
            }
            break;
        case MotionEvent.ACTION_MOVE:
            // 记录到达顶部或底部时手指的位置
            if (!separate) {
                startY = currentY;
            }
            deltaY = currentY - startY;

            // 到达顶部
            if (reachTop) {
                if (!separateFromTop(currentY)) {
                    return super.dispatchTouchEvent(ev);
                }
                return false;
            }
            // 到达底部
            if (reachBottom) {
                if (!separateFromBottom(currentY)) {
                    return super.dispatchTouchEvent(ev);
                }
                return false;
            }
            preY = currentY;
            break;
        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP:
            preY = 0;
            recoverDownView();
            if (separate) {
                separate = false;
                recoverSeparate();
                // 移动,不响应点击事件
                if (move) {
                    move = false;
                    return false;
                }
            }
            break;
        }
        return super.dispatchTouchEvent(ev);
    }

3.在dispatchTouchEvent的MotionEvent.ACTION_MOVE事件中检测有没有滑动到最顶部和最底部,如果滑动到最底部则执行上拉的弹性效果。如果滑动到最顶部则实现下拉的弹性效果。

        case MotionEvent.ACTION_MOVE:
            // 记录到达顶部或底部时手指的位置
            if (!separate) {
                startY = currentY;
            }
            deltaY = currentY - startY;

            // 到达顶部
            if (reachTop) {
                if (!separateFromTop(currentY)) {
                    return super.dispatchTouchEvent(ev);
                }
                return false;
            }
            // 到达底部
            if (reachBottom) {
                if (!separateFromBottom(currentY)) {
                    return super.dispatchTouchEvent(ev);
                }
                return false;
            }
            preY = currentY;
            break;

4.弹性效果的实现,for循环遍历每一个Item,根据每个item的索引(position),计算每一个item在Y方向上的偏移量,在每个item的Y方向执行属性动画。

    for (int index = 0; index < getChildCount(); index++) {
                View child = getChildAt(index);
                int multiple = index;
                if (!separateAll) {
                    if (index > downPosition) {
                        multiple = Math.max(1, downPosition);
                    }
                }
                float distance = multiple * deltaY * FACTOR;
                child.setTranslationY(distance);
            }

5.松开手指,恢复到原来的状态,实现原理:遍历每一个Item实现,将每一个Y方向上的偏移量(offsetY)置为0,通过属性动画将状态复原。

    /**
     * 恢复
     */
    private void recoverSeparate() {
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            ViewPropertyAnimator.animate(child).translationY(0)
                    .setDuration(SEPARATE_RECOVER_DURATION)
                    .setInterpolator(new AccelerateInterpolator());
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值