IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

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

    bt发表于 2023-07-21 14:30:00
    love 0

    系列文章
    造轮子:滚轮选择器实现及原理解析(一)
    造轮子:滚轮选择器实现及原理解析(二)
    造轮子:滚轮选择器实现及原理解析(三)
    造轮子:滚轮选择器实现及原理解析(源码)

    回顾

    造轮子:滚轮选择器实现及原理解析(一)
    上一篇文章我们简单绘制出了基本框图,此篇我们开始尝试使其动起来

    拆解动画

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

    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;
    }

    device-2023-07-21-144210.gif

    惯性动画

    惯性动画当然离不开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);
        }
    }
    

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



沪ICP备19023445号-2号
友情链接