自定義RatingBar

github地址:https://github.com/Ed1sonJ/Ratingbar

實現(xiàn)了的功能:

1明垢、可以自己設(shè)置星星的圖片神得。
2、可以設(shè)置星星之間的padding饥侵。
3鸵赫、可以設(shè)置星星初始的個數(shù)。
4躏升、可以設(shè)置星星的大小辩棒。

為什么要自定義:

1、原生的Ratingbar不能設(shè)置star的padding膨疏。
2一睁、自定義的Ratingbar更加好擴展。

實現(xiàn)的效果:

實現(xiàn)的效果.png

1佃却、設(shè)置自定義屬性

star的總數(shù)量者吁、star的padding、star的size(長寬目前設(shè)置統(tǒng)一)饲帅、star空白的pic复凳、star被點亮的pic、star初始化的數(shù)量灶泵。

<declare-styleable name="Ratingbar">
        <attr name="starNum" format="integer"/>
        <attr name="starPadding" format="dimension"/>
        <attr name="starSize" format="dimension"/>
        <attr name="starEmptyPic" format="reference"/>
        <attr name="starFullPic" format="reference"/>
        <attr name="starInitNum" format="integer"/>
 </declare-styleable>

2育八、計算高寬

計算的公式為:
寬度:左右padding + starPadding *(starNum-1)+ starSize * starNum。
高度:上下padding + starSize丘逸。

//計算寬度
private int measureWidth(int measureSpec) {
        int result;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else {
            //padding + 星星間距*(num-1)+星星大小*num
            result = getPaddingLeft() + getPaddingRight() + starPadding * (starNum - 1) + starSize * starNum;
            if (specMode == MeasureSpec.AT_MOST) {
                result = Math.min(result, specSize);
            }
        }
        return result;
    }
//計算高度
private int measuredHeight(int measureSpec) {
        int result;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else {
            //padding + 星星高度
            result = getPaddingTop() + getPaddingBottom() + starSize;
            if (specMode == MeasureSpec.AT_MOST) {
                result = Math.min(result, specSize);
            }
        }
        return result;
    }

3单鹿、初始繪出星星

3.1,首先繪制星星時要先將畫板移動到特定的位置:
canvas.translate(0, getMeasuredHeight() / 2 - starSize / 2);

將畫板的左上角坐標(biāo)移動到整個View高度的一半再偏上一個pic高度的一半深纲,畫出的圖就能正中顯示在View中。

3.2劲妙,畫出底層的星星(starEmptyPic)
//先畫出灰色的星星
        for (int i = 1; i <= starNum; i++) {
            left = getPaddingLeft() + (i - 1) * starPadding + (i - 1) * starSize;//算出左坐標(biāo)
            canvas.drawBitmap(starEmptyBitmap, left, top, mPaint);
        }
3.3湃鹊,畫出初始化的星星(starFullPic)
//判斷是否第一次初始化,是就畫出默認(rèn)點亮的星星
        if (isFirstDraw) {
            for (int i = 1; i <= starInitNum; i++) {
                left = getPaddingLeft() + (i - 1) * starPadding + (i - 1) * starSize;//算出左坐標(biāo)
                canvas.drawBitmap(starFullBitmap, left, top, mPaint);
            }
        }

isFirstDraw的值在View的觸摸事件上改變镣奋,觸摸View后就不再繪制默認(rèn)點亮的星星币呵。

4、觸摸及滑動畫出點亮的星星

4.1,觸摸事件的處理
@Override
    public boolean onTouchEvent(MotionEvent event) {
        isFirstDraw = false;
        if (isCanTouch) {//可以滑動觸摸
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    caculateStarFullPicNum(event.getX());
                    break;
                case MotionEvent.ACTION_MOVE:
                    caculateStarFullPicNum(event.getX());
                    break;
                case MotionEvent.ACTION_UP:
                    break;
            }
            return true;
        }
        return false;
    }

1.isFirstDraw用于控制onDraw()中是否需要畫出初始化被點亮的星星余赢。
2.isCanTouch提供一個開關(guān)來控制觸摸畫星星芯义。
3.down和move的時候,計算應(yīng)該要畫的星星的數(shù)量妻柒。

4.2扛拨,計算被點亮的星星

計算的方法如下,分3種情況:
1举塔,觸摸的位置在第一個星星的左側(cè)绑警,這時候應(yīng)該顯示最小的星星數(shù)量(通常為0或者1)。
2央渣,觸摸的位置在倒數(shù)第二個星星的末端到View的右邊界计盒,這時候應(yīng)該顯示最大的星星數(shù)量。(為什么這樣想:將一個星星和星星padding看成一個單位長度unitLength芽丹,這樣觸摸到最后邊的星星和View的padding就直接表示為最大的星星數(shù)量)北启。
3,觸摸的位置在第一個星星到第n-1個星星之間拔第,則以第一個星星的左邊界作為X軸坐標(biāo)的原坐標(biāo)咕村,觸摸的長度除以單位長度unitLength再加上1即可計算出要繪制的星星的個數(shù)。

private int starFullPicNum = 1;
    private int unitLength;//一個星星大小加上一個間距

    /**
     * 根據(jù)X軸坐標(biāo)計算當(dāng)前的星星num
     *
     * @param startX
     */
    private void caculateStarFullPicNum(float startX) {
        if (startX < getPaddingLeft()) {//觸摸位置在星星左側(cè)
            starFullPicNum = DEFAULT_STAR_MININUM;
        } else if (startX > (getMeasuredWidth() - getPaddingRight() - starSize)) {//觸摸位置在右側(cè)星星邊界加上倒數(shù)第一個星星的距離
            starFullPicNum = starNum;
        } else {//觸摸在第一個星星到第(n-1)個星星之間楼肪,用坐標(biāo)軸的思想考慮
            starFullPicNum = (int) ((startX - getPaddingLeft()) / unitLength) + 1;
        }
        if (listener != null) {
            listener.OnStarChange(starFullPicNum);
        }
        invalidate();
        Logger.e("Ratingbar:要繪制的星星數(shù)量:" + starFullPicNum);
    }

5培廓、收尾工作

5.1,提供接口回調(diào)春叫,當(dāng)繪制的星星數(shù)量改變時回調(diào)出去肩钠。
5.2,向外提供設(shè)置當(dāng)前要繪制星星的方法暂殖,方便設(shè)置了不能觸摸時可以直接通過方法設(shè)置价匠。
/**
     * 設(shè)置畫的星星num,并重畫
     */
    public void setCurrentStarFullNum(int num) {
        this.starFullPicNum = num;
        invalidate();
    }
5.3呛每,向外提供設(shè)置能否觸摸來繪制星星的開關(guān)
/**
     * 設(shè)置能否滑動
     */
    public void setIsCanTouch(Boolean isCanTouch) {
        this.isCanTouch = isCanTouch;
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末踩窖,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子晨横,更是在濱河造成了極大的恐慌洋腮,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件手形,死亡現(xiàn)場離奇詭異啥供,居然都是意外死亡,警方通過查閱死者的電腦和手機库糠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進店門伙狐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事贷屎“辗溃” “怎么了?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵唉侄,是天一觀的道長咒吐。 經(jīng)常有香客問我,道長美旧,這世上最難降的妖魔是什么渤滞? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮榴嗅,結(jié)果婚禮上妄呕,老公的妹妹穿的比我還像新娘。我一直安慰自己嗽测,他們只是感情好绪励,可當(dāng)我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著唠粥,像睡著了一般疏魏。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上晤愧,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天大莫,我揣著相機與錄音,去河邊找鬼官份。 笑死只厘,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的舅巷。 我是一名探鬼主播羔味,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼掏愁,長吁一口氣:“原來是場噩夢啊……” “哼全景!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起泰演,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤飒房,失蹤者是張志新(化名)和其女友劉穎搁凸,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體狠毯,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡坪仇,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了垃你。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖惜颇,靈堂內(nèi)的尸體忽然破棺而出皆刺,到底是詐尸還是另有隱情,我是刑警寧澤凌摄,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布羡蛾,位于F島的核電站,受9級特大地震影響锨亏,放射性物質(zhì)發(fā)生泄漏痴怨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一器予、第九天 我趴在偏房一處隱蔽的房頂上張望浪藻。 院中可真熱鬧,春花似錦乾翔、人聲如沸爱葵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽萌丈。三九已至,卻和暖如春雷则,著一層夾襖步出監(jiān)牢的瞬間辆雾,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工月劈, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留度迂,地道東北人。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓艺栈,卻偏偏與公主長得像英岭,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子湿右,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,601評論 2 353

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

  • 最近項目開發(fā)過程中遇到一個小問題诅妹,之前沒用過系統(tǒng)原生的RatingBar這個控件,這次在使用的時候發(fā)現(xiàn)原生的支持并...
    Leo618閱讀 3,238評論 0 3
  • RatingBar是基于SeekBar(拖動條)和ProgressBar(狀態(tài)條)的擴展毅人,用星形來顯示等級評定吭狡! ...
    腦袋君閱讀 24,517評論 15 42
  • 使用Ratingbar做一個完成度的評定顯示:系統(tǒng)默認(rèn)的Ratingbar顏色并不合適使用。此處需要自定義丈莺。參考網(wǎng)...
    V_boomboom閱讀 1,793評論 0 1
  • 樣式 android系統(tǒng)自帶了三種RatingBar的樣式style="@android:style/Widget...
    Ted_Wang閱讀 1,002評論 0 0
  • 剪刀已經(jīng)成為大丫頭日常生活中必不可少的一個工具划煮。最近我們一起玩剪紙,更加刷新了剪刀的存在感缔俄,同時也刷出了丫頭滿滿的...
    馨容媽媽閱讀 188評論 0 0