Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 管窺Android中的滑動條SeekBar的父類AbsSeekBar的源碼

管窺Android中的滑動條SeekBar的父類AbsSeekBar的源碼

編輯:關於Android編程

Android中的控件中有一類是ProgressBar,其子類中有一個是AbsSeekBar。相信有不少童鞋對這個拖動條的父類比較感興趣吧!尤其是看到網易雲音樂的進度條上面是可以處理播放與暫停事件,是不是很羨慕的哈~ 俺在這裡告訴大家,不用羨慕,看了我下面的代碼分析,你也是可以做出那樣的效果的哦。Let's go.

下面先給大家列表一下AbsSeekBar的成員變量有哪些。

    //當前的矩形
    private final Rect mTempRect = new Rect();
    //可以拖動的滑塊
    private Drawable mThumb;
    //顏色的狀態的列表
    private ColorStateList mThumbTintList = null;
    //對應的端口的融合
    private PorterDuff.Mode mThumbTintMode = null;
    //是否支持的歡快的tint
    private boolean mHasThumbTint = false;
    //對應的是滑塊的模式
    private boolean mHasThumbTintMode = false;
    //滑塊的偏移量
    private int mThumbOffset;
    //是否進行分割追蹤
    private boolean mSplitTrack;
在變量中我們大致需要知道一下幾點:

1、mTempRect是與SeekBar整個軌跡繪制相關的變量

2、mThumb是SeekBar上面的滑塊的Drawable的圖片

3、mThumbOffset是滑塊是距離x左邊距的距離


對於AbsSeekBar的成員方法,下面選取一個比較重要的,在實際的開發工作中經常用到的幾個方法給大家講解一下。

1、setThumbOffset

這個方法是設置滑塊距離左邊距的位置

2、

public synchronized void setMax(int max) {
        super.setMax(max);
        if ((mKeyProgressIncrement == 0) || (getMax() / mKeyProgressIncrement > 20)) {
            // It will take the user too long to change this via keys, change it
            // to something more reasonable
            //設置為比較合理的數值
            setKeyProgressIncrement(Math.max(1, Math.round((float) getMax() / 20)));
        }
    }

這個方法實際關聯到兩個功能。

1、設置當前的SeekBar的最大值

2、由於存在部分手機有向左的按鍵與向右的按鍵,就比如我曾經遇到過的一款三星的商務機。按照源碼的邏輯,控制左按鍵與右按鍵一次位移的邊距不要超過20.

關於軌跡的繪制與滑塊的繪制的更新,主要關注下面的一段代碼

if (track != null) {
            track.setBounds(0, trackOffset, w - mPaddingRight - mPaddingLeft,
                    h - mPaddingBottom - trackOffset - mPaddingTop);
        }
        if (thumb != null) {
            setThumbPos(w, thumb, getScale(), thumbOffset);
        }

軌跡的繪制比較重要,我們一起看看吧;

void drawTrack(Canvas canvas) {
        //獲取當前滑塊的引用
        final Drawable thumbDrawable = mThumb;
        if (thumbDrawable != null && mSplitTrack) {
            final Insets insets = thumbDrawable.getOpticalInsets();
            final Rect tempRect = mTempRect;
            thumbDrawable.copyBounds(tempRect);
            tempRect.offset(mPaddingLeft - mThumbOffset, mPaddingTop);
            tempRect.left += insets.left;
            tempRect.right -= insets.right;

            final int saveCount = canvas.save();
            //對當前的矩形進行裁剪
            canvas.clipRect(tempRect, Op.DIFFERENCE);
            super.drawTrack(canvas);
            canvas.restoreToCount(saveCount);
        } else {
            super.drawTrack(canvas);
        }
    }
針對上面的代碼塊,主要講下面的幾點:

1、mSlitTrack這個變量存在的原因是,我們通常遇到滑塊的左右的顏色不一樣,這個變量就是起到分割左右兩邊的目的。

滑塊的繪制也是比較重要的哦,下面也一起來看看吧:

void drawThumb(Canvas canvas) {
        if (mThumb != null) {
            canvas.save();
            // Translate the padding. For the x, we need to allow the thumb to
            // draw in its extra space
            //主要是x軸上面的變化
            canvas.translate(mPaddingLeft - mThumbOffset, mPaddingTop);
            //繪制一些Canvas的對象
            mThumb.draw(canvas);
            canvas.restore();
        }
    }

我們知道,滑塊的位置會隨著進度而不斷的位移,而繪制的本質實際上都利用了畫布類Canvas,因此本質上是畫布在不斷的進行位移。也就是這一行代碼的含義:
canvas.translate(mPaddingLeft - mThumbOffset, mPaddingTop);
下面的內容主要是講解AbsSeekBar是如何處理touch事件,而我上面的所說的網易雲音樂如果做到點擊進度條實現播放與暫停的效果也與下面的講解有關:

與上面一樣,咱們先上代碼:

public boolean onTouchEvent(MotionEvent event) {
        if (!mIsUserSeekable || !isEnabled()) {
            return false;
        }

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (isInScrollingContainer()) {
                    mTouchDownX = event.getX();
                } else {
                    //設置當前的狀態是處於按下的狀態
                    setPressed(true);
                    if (mThumb != null) {
                        invalidate(mThumb.getBounds()); // This may be within the padding region
                    }
                    onStartTrackingTouch();
                    trackTouchEvent(event);
                    attemptClaimDrag();
                }
                break;

            case MotionEvent.ACTION_MOVE:
                if (mIsDragging) {
                    trackTouchEvent(event);
                } else {
                    final float x = event.getX();
                    //超過一定的狀態
                    if (Math.abs(x - mTouchDownX) > mScaledTouchSlop) {
                        setPressed(true);
                        if (mThumb != null) {
                            invalidate(mThumb.getBounds()); // This may be within the padding region
                        }
                        onStartTrackingTouch();
                        trackTouchEvent(event);
                        attemptClaimDrag();
                    }
                }
                break;

            case MotionEvent.ACTION_UP:
                if (mIsDragging) {
                    trackTouchEvent(event);
                    onStopTrackingTouch();
                    setPressed(false);
                } else {
                    // Touch up when we never crossed the touch slop threshold should
                    // be interpreted as a tap-seek to that location.
                    onStartTrackingTouch();
                    trackTouchEvent(event);
                    onStopTrackingTouch();
                }
                // ProgressBar doesn't know to repaint the thumb drawable
                // in its inactive state when the touch stops (because the
                // value has not apparently changed)
                invalidate();
                break;

            case MotionEvent.ACTION_CANCEL:
                if (mIsDragging) {
                    onStopTrackingTouch();
                    setPressed(false);
                }
                invalidate(); // see above explanation
                break;
        }
        return true;
    }

上面的代碼,各位看官不要著急,且聽在下一一道來:

1、如果當前的SeekBar已經設置了不能夠touch操作,廢話不用多說,直接return。

2、按照源碼的解釋,當當前的控件處於按下的狀態,主要進行下面的處理:

2、1 設置當前的狀態為Press的狀態

2、2 刷新當前的視圖


如果我們需要仿造網易雲音樂,需要處理暫停音樂的邏輯,

需要注意兩點

1、判斷當前的event的x的坐標是否是在滑塊的內部,如果是,不論當前的位移是多少,均不要改變當前的進度

2、修改當前的滑塊的圖片



好了,整個的源碼的講解就到這裡了,相信大家看到這裡,對Android中的SeekBar有了比以前更進一步的了解了吧!不用謝哦,叫我發哥就行。再見,



  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved