github(四)android下wheelview源码分析

 wheelview是一款模拟ios的缩放滑动的控件,

 wheelview 继承于View父布局,整个布局是画出来的,

一、构造函数初始化

1.1构造函数进行了以下的操作,对CENTER_CONTENT_OFFSET(偏移量)进行适配,

   DisplayMetrics dm = getResources().getDisplayMetrics();
        float density = dm.density; // 屏幕密度比(0.75/1.0/1.5/2.0/3.0)

        if (density < 1) {//根据密度不同进行适配
            CENTER_CONTENT_OFFSET = 2.4F;
        } else if (1 <= density && density < 2) {
            CENTER_CONTENT_OFFSET = 3.6F;
        } else if (1 <= density && density < 2) {
            CENTER_CONTENT_OFFSET = 4.5F;
        } else if (2 <= density && density < 3) {
            CENTER_CONTENT_OFFSET = 6.0F;
        } else if (density >= 3) {
            CENTER_CONTENT_OFFSET = density * 2.5F;
        }

1.2 lineSpacingMultiplier,间距倍数,绘制的两条线的距离

    /**
     * 判断间距是否在1.0-4.0之间
     */
    private void judgeLineSpace() {
        if (lineSpacingMultiplier < 1.0f) {
            lineSpacingMultiplier = 1.0f;
        } else if (lineSpacingMultiplier > 4.0f) {
            lineSpacingMultiplier = 4.0f;
        }
    }

1.3 initLoopView是初始化 消息、手势,以及画笔的内容。


    private void initLoopView(Context context) {
        this.context = context;
        handler = new MessageHandler(this);
        gestureDetector = new GestureDetector(context, new LoopViewGestureListener(this));
        gestureDetector.setIsLongpressEnabled(false);
        isLoop = true;

        totalScrollY = 0;
        initPosition = -1;
        initPaints();
    }

二、测量方法

测量的方法有以下几个reMeasure,

1.1 reMeasure,第一步实现了对单个item的宽度和高度的测量,这个方法是在setAdapter和onMeasure时执行了,当数据更新时是要重新测试高度的

1.2

三、绘制方法

由于这个是继承于View的,所以所有的条目以及横线都是绘制生成的,

3.1.1 计算滚动了多少个Item,是从当前所在位置计算的

 change = (int) (totalScrollY / itemHeight);

3.1.2 绘制中间两条线

 //绘制中间两条横线
        if (dividerType == DividerType.WRAP) {//横线长度仅包裹内容
            float startX;
            float endX;

            if (TextUtils.isEmpty(label)) {//隐藏Label的情况
                startX = (measuredWidth - maxTextWidth) / 2 - 12;
            } else {
                startX = (measuredWidth - maxTextWidth) / 4 - 12;
            }

            if (startX <= 0) {//如果超过了WheelView的边缘
                startX = 10;
            }
            endX = measuredWidth - startX;
            canvas.drawLine(startX, firstLineY, endX, firstLineY, paintIndicator);
            canvas.drawLine(startX, secondLineY, endX, secondLineY, paintIndicator);
        } else {
            //Todo 画线
            canvas.drawLine(0.0F, firstLineY, measuredWidth, firstLineY, paintIndicator);
            canvas.drawLine(0.0F, secondLineY+100, measuredWidth, secondLineY+100, paintIndicator);
        }

四、滚动的方法

4.1 onTouch方法

 使用了gestureDetector手势,

4.1.1   MotionEvent.ACTION_DOWN,

初始化开始时间,执行cancelFuture()方法,停止滚动,获取停止座标previousY = event.getRawY();

4.1.2 MotionEvent.ACTION_MOVE:

通过previousY - event.getRawY(),计算出来移动的Y的距离,totalScrollY记录移动的总的距离,这里是有计算缩放的方法的,应该是利用圆的半径来计算的。

   if (!eventConsumed) {//未消费掉事件

                    /**
                     *@describe <关于弧长的计算>
                     *
                     * 弧长公式: L = α*R
                     * 反余弦公式:arccos(cosα) = α
                     * 由于之前是有顺时针偏移90度,
                     * 所以实际弧度范围α2的值 :α2 = π/2-α    (α=[0,π] α2 = [-π/2,π/2])
                     * 根据正弦余弦转换公式 cosα = sin(π/2-α)
                     * 代入,得: cosα = sin(π/2-α) = sinα2 = (R - y) / R
                     * 所以弧长 L = arccos(cosα)*R = arccos((R - y) / R)*R
                     */

                    float y = event.getY();
                    double L = Math.acos((radius - y) / radius) * radius;
                    //item0 有一半是在不可见区域,所以需要加上 itemHeight / 2
                    int circlePosition = (int) ((L + itemHeight / 2) / itemHeight);
                    float extraOffset = (totalScrollY % itemHeight + itemHeight) % itemHeight;
                    //已滑动的弧长值
                    mOffset = (int) ((circlePosition - itemsVisible / 2) * itemHeight - extraOffset);

                    if ((System.currentTimeMillis() - startTime) > 120) {
                        // 处理拖拽事件
                        smoothScroll(ACTION.DAGGLE);
                    } else {
                        // 处理条目点击事件
                        smoothScroll(ACTION.CLICK);
                    }
                }

五、各个值的分析

totalScrollY:表示滚动的距离,初始化为0,向上滚动增加 dy,向上dy为正,向下为负

itemHeightOffset:totalScrollY % itemHeight,是滚动距离的相对于itemHeight的偏移量,是多余的部门,算弧长的时候要减去这个值。

top:-initPosition * itemHeight,计算出来顶部的距离

bottom:计算出来底部的最低位置

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章