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:計算出來底部的最低位置

 

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