自定義ScaleSeekBar

android系統(tǒng)提供的原生seekbar使用起來并不是那么好艰躺,例如可拖拽區(qū)域很小廊勃、沒有刻度。
最近項(xiàng)目里面設(shè)計(jì)提供了的設(shè)計(jì)圖就有一個(gè)seekbar犀忱,seekbar上有刻度,當(dāng)手指移動(dòng)到刻度附近時(shí)郊供,刻度條就會(huì)移動(dòng)到指定的刻度附近峡碉。,同時(shí)驮审,會(huì)有一個(gè)回調(diào)通知進(jìn)度的改變鲫寄。
接到這個(gè)需求后,在github上找了一圈疯淫,發(fā)現(xiàn)現(xiàn)有的seekbar提供的功能太多地来,與需求不符合,故自己寫了一個(gè)熙掺。

實(shí)現(xiàn)的效果圖如下未斑。
screenshot.png

項(xiàng)目地址:scaleseekbar

首先看在布局文件里面怎么使用:

 <com.cheng.scaleseekbar.ScaleSeekBar
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:paddingTop="8dp"
        android:paddingBottom="8dp"
        android:paddingLeft="10dp"
        android:paddingRight="10dp"
        android:id="@+id/seek_bar"
        android:layout_marginLeft="30dp"
        android:layout_marginRight="30dp"
        app:layout_constraintTop_toBottomOf="@+id/text"
        tools:layout_editor_absoluteX="8dp"/>

由于進(jìn)度條需要一定的寬度來展示,在這里直接寫死了高度和padding值币绩,實(shí)際可以在自定義view里面做特殊處理蜡秽。

init()函數(shù) 初始化

//定義畫筆
 mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaintWidth = Util.dipToPixel(2);
        mPaint.setStrokeWidth(mPaintWidth);
       // 左右邊距
        mSpace = Util.dipToPixel(12);
        //一共畫5個(gè)點(diǎn)
        mPointNum = 5;
       //獲得小圓的半徑
        mSmallCircleRadius = Util.dipToPixel(4);
       //獲得當(dāng)前指示條的內(nèi)半徑(比較明顯的顏色)
        mBigCircleInnerRadius = Util.dipToPixel(8);
         //獲得當(dāng)前指示條的外半徑(比較淡的顏色)
        mBigCircleOuterRadius = Util.dipToPixel(10);
        //因?yàn)橐A(yù)留空位給外圈的大圓
        mPaddingTop = getPaddingTop() + mBigCircleOuterRadius;

定義了上述屬性后,接著需要獲得各個(gè)點(diǎn)的坐標(biāo)缆镣。我們在OnMeasure后獲取控件的寬高芽突,同時(shí)確定各個(gè)點(diǎn)的位置。

super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //控件寬度
        mWidth = getMeasuredWidth();
        //去除左右邊距后留給seekbar的繪制區(qū)間
        mLength = mWidth - mSpace * 2;// 
        mSegmentLength = mLength / (mPointNum - 1);// 5個(gè)點(diǎn)分割成4段 每段的長度
        mEndPoint = mSpace + (mSegmentLength * (mPointNum - 1));//終止點(diǎn)的位置.

提供接口給外部調(diào)用設(shè)置當(dāng)前的進(jìn)度條董瞻。(總進(jìn)度為5寞蚌, 這里progress的取值為0~4,這里可以假設(shè)默認(rèn)值為2)

public void setProgress(int progress) {
        this.mNewProgress = progress;
    }

獲取完每個(gè)點(diǎn)的坐標(biāo)位置、線段的起止值钠糊,圓的半徑以及當(dāng)前的進(jìn)度后挟秤,我們就可以在ondraw()里面進(jìn)行繪制了。

super.onDraw(canvas);
        this.mPaint.setColor(this.mColors[1]);
       //根據(jù)線段起止點(diǎn)繪制一條線
        canvas.drawLine(this.mSpace, this.mSpace + this.mPaddingTop, this.mEndPoint, this.mSpace + this.mPaddingTop, this.mPaint);// 整體繪制一條灰色線貫穿整體
        this.mPaint.setColor(this.mColors[0]);
        //在起始點(diǎn)話了一個(gè)小圓抄伍。
        canvas.drawCircle(this.mSpace, this.mSpace + this.mPaddingTop, mSmallCircleRadius, this.mPaint);//畫了一個(gè)小圓環(huán)
        //根據(jù)mNewProgress的值確定當(dāng)前的進(jìn)度條所在的終點(diǎn)艘刚,繪制一條從起點(diǎn)到進(jìn)度終點(diǎn)的線
        canvas.drawLine(this.mSpace, this.mSpace + this.mPaddingTop, this.mSpace + this.mSegmentLength * this.mNewProgress, this.mSpace + this.mPaddingTop, this.mPaint); // 根據(jù)進(jìn)度條畫了新的顏色線
        int index = 1;
        //根據(jù)mNowProgress的值,小于mNowProgress的值繪制藍(lán)色圓圈截珍,大于mNowProgress的繪制灰色圓圈昔脯。
        if (index < this.mPointNum) {
            for (; index < this.mPointNum; index++) {
                if (this.mNewProgress > index) {
                    this.mPaint.setColor(this.mColors[0]);
                } else {
                    this.mPaint.setColor(this.mColors[1]);
                }
                canvas.drawCircle(this.mSpace + index * mSegmentLength, this.mSpace + this.mPaddingTop, mSmallCircleRadius, this.mPaint);//每個(gè)位置畫一個(gè)小圓 顏色不一樣
            }

        }
        this.mPaint.setColor(this.mCircleColor[1]);
       //在mNewProgress的地方繪制一個(gè)顏色比較淺的大圓啄糙,再繪制一個(gè)顏色比較深的大圓  
        canvas.drawCircle(this.mSpace + this.mSegmentLength * this.mNewProgress, this.mSpace + this.mPaddingTop, this.mBigCircleOuterRadius, this.mPaint);
        this.mPaint.setColor(this.mCircleColor[0]);
        canvas.drawCircle(this.mSpace + this.mSegmentLength * this.mNewProgress, this.mSpace + this.mPaddingTop, this.mBigCircleInnerRadius, this.mPaint);
      //通過這樣的方式,所有我們需要繪制的內(nèi)容已經(jīng)繪制完畢

前面已經(jīng)做到了根據(jù)當(dāng)前進(jìn)度分別繪制不同的內(nèi)容到canvas上云稚。
接下來需要響應(yīng)用戶的滑動(dòng)手勢,根據(jù)手勢滑動(dòng)的地方判斷當(dāng)前進(jìn)度值沈堡。

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        int x = (int) event.getX();
        //滑動(dòng)事件開始的時(shí)候静陈,傳遞x的坐標(biāo)值,后面的notifydatachanged方法根據(jù)該值判斷是否滑動(dòng)到了臨界點(diǎn)诞丽,如果到了鲸拥,給外部的監(jiān)聽事件發(fā)通知。
        notifyDataChanged(x);
        return true;

    }
   
    //這里根據(jù)x值判斷當(dāng)前滑動(dòng)到了哪個(gè)點(diǎn)僧免,更新mNewProgress的值,同時(shí)通知view進(jìn)行重繪(這里應(yīng)該保留以前的值刑赶,避免每次都重繪)
    private void notifyDataChanged(int x) {
        this.mNewProgress = (this.mSegmentLength / 3 + x - mSpace) / this.mSegmentLength;
        if ((this.mListener != null)) {
            this.mListener.notifyProgressChanged(this.mNewProgress);
        }
        invalidate();
    }

public interface ProgressListener {
        void notifyProgressChanged(int progress);
    }

這里就將seekbar的坐標(biāo)點(diǎn)確定、進(jìn)度條繪制懂衩、響應(yīng)touch事件完成撞叨,并完成了事件改變的通知。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末浊洞,一起剝皮案震驚了整個(gè)濱河市牵敷,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌腰鬼,老刑警劉巖泻轰,帶你破解...
    沈念sama閱讀 221,820評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件注盈,死亡現(xiàn)場離奇詭異,居然都是意外死亡毛肋,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門屋剑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來润匙,“玉大人,你說我怎么就攤上這事饼丘〕锰遥” “怎么了?”我有些...
    開封第一講書人閱讀 168,324評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵肄鸽,是天一觀的道長卫病。 經(jīng)常有香客問我,道長典徘,這世上最難降的妖魔是什么蟀苛? 我笑而不...
    開封第一講書人閱讀 59,714評(píng)論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮逮诲,結(jié)果婚禮上帜平,老公的妹妹穿的比我還像新娘幽告。我一直安慰自己,他們只是感情好裆甩,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,724評(píng)論 6 397
  • 文/花漫 我一把揭開白布冗锁。 她就那樣靜靜地躺著,像睡著了一般嗤栓。 火紅的嫁衣襯著肌膚如雪冻河。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,328評(píng)論 1 310
  • 那天茉帅,我揣著相機(jī)與錄音叨叙,去河邊找鬼。 笑死堪澎,一個(gè)胖子當(dāng)著我的面吹牛擂错,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播樱蛤,決...
    沈念sama閱讀 40,897評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼钮呀,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了刹悴?” 一聲冷哼從身側(cè)響起行楞,我...
    開封第一講書人閱讀 39,804評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎土匀,沒想到半個(gè)月后子房,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,345評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡就轧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,431評(píng)論 3 340
  • 正文 我和宋清朗相戀三年证杭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片妒御。...
    茶點(diǎn)故事閱讀 40,561評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡解愤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出乎莉,到底是詐尸還是另有隱情送讲,我是刑警寧澤,帶...
    沈念sama閱讀 36,238評(píng)論 5 350
  • 正文 年R本政府宣布惋啃,位于F島的核電站哼鬓,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏边灭。R本人自食惡果不足惜异希,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,928評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望绒瘦。 院中可真熱鬧称簿,春花似錦扣癣、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至券册,卻和暖如春频轿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背烁焙。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留耕赘,地道東北人骄蝇。 一個(gè)月前我還...
    沈念sama閱讀 48,983評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像操骡,于是被迫代替她去往敵國和親九火。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,573評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容