造轮子:滚轮选择器实现及原理解析(二)

造轮子:滚轮选择器实现及原理解析(二)

回顾

https://www.ccc2.icu/archives/KfYE1FDz

上一篇文章我们简单绘制出了基本框图,此篇我们开始尝试使其动起来

拆解动画

体验过滚轮选择器的同学应该能感受到,滚轮存在着多种动画,这次我们只处理和交互相关的动画,其他动画放到下一节分析

1. 跟手动画 - 手拖动到哪就跟随滚动到哪

2. 惯性动画 - 松手后一段时间内仍可滚动,速度慢慢降低

3. 吸附动画 - 速度降低到一定数值时,使其吸附到就近的一个item上

跟手动画

说到跟手动画,那一定是放到touch事件里处理,我们的处理方式也和常规拖动监听一样简单,拖动时实时修curY的位置,并刷新页面。这里新增了一scrollState 存储当前状态。

@Override

public boolean onTouchEvent(MotionEvent event) {

    switch (event.getAction()) {

        case MotionEvent.ACTION_DOWN:

            // 重置状态

            scrollState = SCROLL_STATE_NORMAL;

            lastY = event.getY();

            startY = event.getY();

            break;

        case MotionEvent.ACTION_MOVE:

            curY -= event.getY() - lastY;

            // 调整y使其不超出边界

            curY = adjustingY(curY);

            lastY = event.getY();

            invalidate();

            break;

        default:

            break;

    }

    return true;

}

惯性动画

惯性动画当然离不Scroller,使Scroller传入速度很容易使其实时帮助计算出当前惯性距离

调整一下onTouch事件

public boolean onTouchEvent(MotionEvent event) {

    // 速度监听

    velocityTracker.addMovement(event);

    switch (event.getAction()) {  

        ...    

        case MotionEvent.ACTION_UP:

            curY -= event.getY() - lastY;

            // 调整y使其不超出边界

            curY = adjustingY(curY);

            lastY = event.getY();

            // 计算速度,根据速度决定惯性滚动还是吸附

            velocityTracker.computeCurrentVelocity(1000, 2000);

            checkTouch((int) velocityTracker.getXVelocity(), (int) velocityTracker.getYVelocity());

            break;

        default:

            break;

    }

    return true;

}

在调用scroller.fling方法后,会基于Y方向的速度进行实时计算,我们computeScroll方法里对当前y值进行计算赋值,逻辑类似于拖拽时的计算,代码就不放了,感兴趣的可以直接看源码。

吸附动画

在开始滚动但是速度不足的场景,或滚动时速度慢慢变慢的场景下,需要使其吸附到最近的item上,逻辑很简单,直接上代码

public void startAdsorbAnim() {

    float y = curY;

    int centerPosition = getCenterShowPosition(y);

    float offsetY = adjustingY(y) - itemHeight * centerPosition;

    int newPosition;

    // 超出一半时吸附到下一个item

    if (offsetY >= itemHeight / 2f) {

        // 封装的动画,本质是ValueAnimator

        manager.playAnim(KEY_PICKER_ADSORB_ANIM, curY, curY + itemHeight - offsetY);

        newPosition = adjustingPosition(centerPosition + 1);

    } else {

       // 封装的动画,本质是ValueAnimator

        manager.playAnim(KEY_PICKER_ADSORB_ANIM, curY, curY - offsetY);

        newPosition = adjustingPosition(centerPosition);

    }

    if (pickerChangeListener != null && curPosition != newPosition) {

        curPosition = newPosition;

        pickerChangeListener.onPickerSelectedChanged(this, curPosition, data[curPosition], true);

    }

}

至此,能够完成基本的动画,使其看起来起码像一个滚轮了,下一篇我们开始优化细节,使其易用,美观

造轮子:滚轮选择器实现及原理解析(一) 2023-07-21
造轮子:滚轮选择器实现及原理解析(三) 2023-07-23

评论区