Kotlin實現(xiàn)自定義RatingBar

好久沒分享過了,突然感覺手都有點生疏了昂利。最近需求ratingbar顯示規(guī)則為:0為空星,1為全星铁坎,0.5為半星蜂奸,小于0.5為小半星,大于0.5則為大半星硬萍。對于這個需求第一感覺就是使用系統(tǒng)自帶RatingBar扩所,但在使用過程中發(fā)現(xiàn)其只能實現(xiàn)空星、半星朴乖、全星祖屏,其所自帶的android:stepSize=""android:rating=""屬性并不能很好的實現(xiàn)此種需求效果,并且網(wǎng)上實現(xiàn)的自定義Ratingbar寒砖,基本都是通過繼承LinearLayout赐劣,內(nèi)部創(chuàng)建ImageView來實現(xiàn)的嫉拐,個人感覺這樣實現(xiàn)不是特別好哩都,于是決定自己動手豐衣足食。
基本思路是:通過繼承View完全自定來實現(xiàn)(onMeasure婉徘、onDraw來手動測繪)漠嵌。好了咐汞,bibi了這么多,還是先看效果圖吧儒鹿。

custom_rating_bar.png

效果就是如上化撕,基本需求已經(jīng)滿足了,嘿嘿约炎。
下面我們來看看它的實現(xiàn)過程吧植阴,基本就是擼代碼啦。圾浅。掠手。

//空星
private const val NONE = 0
//半星
private const val HALF = 1
//小半星
private const val HALF_LOW = 2
//大半星
private const val HALF_OVER = 3

//默認進度
private const val DEFAULT_RATING = 0.0f
//默認星星個數(shù)
private const val DEFAULT_NUM_STARS = 5
//默認星星間間距
private const val DEAFULT_SPACE_BETWEEN = 0.0f

class CustomeRatingBar : View {

    //星星進度
    var rating: Float = DEFAULT_RATING
        set(value) {
            field = value
            invalidate()
        }

    //星星總數(shù)
    var numStars: Int = DEFAULT_NUM_STARS
        set(value) {
            field = value
            invalidate()
        }

    //星星間距
    var spaceBetween: Float = DEAFULT_SPACE_BETWEEN
        set(value) {
            field = value
            invalidate()
        }

    //空星drawable
    private var mStrokeStar: BitmapDrawable? = null
    //實星drawable
    private var mFullStar: BitmapDrawable? = null
    //半星drawable
    private var mHalfStar: BitmapDrawable? = null
    //小半星drawable
    private var mHalfLowStar: BitmapDrawable? = null
    //大半星drawable
    private var mHalfOverStar: BitmapDrawable? = null

    private val mPaint by lazy {
        Paint(Paint.ANTI_ALIAS_FLAG)
    }


    constructor(context: Context?) : super(context)

    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {
        initAttributeSet(attrs)
    }

    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
        initAttributeSet(attrs)
    }

    private fun initAttributeSet(attrs: AttributeSet?) {
        context?.obtainStyledAttributes(attrs, R.styleable.CustomerRatingBar)?.let {
            try {
                rating = it.getFloat(R.styleable.CustomerRatingBar_rating, DEFAULT_RATING)
                numStars = it.getInt(R.styleable.CustomerRatingBar_numStars, DEFAULT_NUM_STARS)
                mStrokeStar = it.getDrawable(R.styleable.CustomerRatingBar_strokeStar) as BitmapDrawable?
                mFullStar = it.getDrawable(R.styleable.CustomerRatingBar_fullStar) as BitmapDrawable?
                mHalfStar = it.getDrawable(R.styleable.CustomerRatingBar_halfStar) as BitmapDrawable?
                mHalfLowStar = it.getDrawable(R.styleable.CustomerRatingBar_halfLowStar) as BitmapDrawable?
                mHalfOverStar = it.getDrawable(R.styleable.CustomerRatingBar_halfOverStar) as BitmapDrawable?
                spaceBetween = it.getDimension(R.styleable.CustomerRatingBar_spaceBetween, DEAFULT_SPACE_BETWEEN)
            } finally {
                it.recycle()
            }
            if (mStrokeStar == null) {
                throw IllegalArgumentException("must set stroke star drawable")
            }
            if (mHalfStar == null) {
                throw IllegalArgumentException("must set half star drawable")
            }
            if (mFullStar == null) {
                throw IllegalArgumentException("must set full star drawable")
            }
        }
    }

    fun setStrokeStar(resStrokeStar: Int) {
        mStrokeStar = resources.getDrawable(resStrokeStar) as BitmapDrawable?
    }

    fun setFullStar(resFullStar: Int) {
        mFullStar = resources.getDrawable(resFullStar) as BitmapDrawable?
    }

    fun setHalfStar(resHalfStar: Int) {
        mHalfStar = resources.getDrawable(resHalfStar) as BitmapDrawable?
    }

    fun setHalfLowStar(resHalfLosStar: Int) {
        mHalfLowStar = resources.getDrawable(resHalfLosStar) as BitmapDrawable?
    }

    fun setHalfOverStar(resHalfOverStar: Int) {
        mHalfOverStar = resources.getDrawable(resHalfOverStar) as BitmapDrawable?
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        var width = MeasureSpec.getSize(widthMeasureSpec)
        var height = mStrokeStar?.bitmap?.height ?: 0

        if (MeasureSpec.AT_MOST == MeasureSpec.getMode(widthMeasureSpec)) {
            width = mStrokeStar?.bitmap?.let {
                it.width * numStars + (spaceBetween * (numStars - 1) + 0.5f).toInt()
            } ?: 0
        }

        if (MeasureSpec.EXACTLY == MeasureSpec.getMode(heightMeasureSpec)) {
            height = MeasureSpec.getSize(heightMeasureSpec)
        }

        setMeasuredDimension(width, height)
    }

    override fun onDraw(canvas: Canvas?) {
        var bitmap: Bitmap? = null
        for (index in 0 until numStars) {
            if (index < getFullStarCount()) {
                //繪制全星
                bitmap = mFullStar?.bitmap
            } else {
                if (getFullStarCount() == index) {
                    //繪制進度最后一個星星
                    when (getLastProgressType()) {
                        NONE -> bitmap = mStrokeStar?.bitmap
                        HALF -> bitmap = mHalfStar?.bitmap
                        HALF_LOW -> bitmap = mHalfLowStar?.bitmap
                        HALF_OVER -> bitmap = mHalfOverStar?.bitmap
                    }
                } else {
                    //繪制剩余空星
                    bitmap = mStrokeStar?.bitmap
                }
            }
            bitmap?.let {
                canvas?.drawBitmap(it, index * (it.width + spaceBetween), 0.0f, mPaint)
            }
        }
    }

    /**
     * 獲取進度全星個數(shù)
     */
    private fun getFullStarCount() = rating.toInt()

    /**
     * 獲取進度最后一個星星類型
     */
    private fun getLastProgressType() = (rating - getFullStarCount()).let {
        when {
            it == 0.0f -> NONE
            it > 0.5f -> mHalfOverStar?.let { HALF_OVER } ?: HALF
            it < 0.5f -> mHalfLowStar?.let { HALF_LOW } ?: HALF
            else -> HALF
        }
    }
}

自定義屬性如下:

<declare-styleable name="CustomerRatingBar">
        <attr name="rating" format="float"/>
        <attr name="numStars" format="integer"/>
        <attr name="strokeStar" format="reference"/>
        <attr name="fullStar" format="reference"/>
        <attr name="halfStar" format="reference"/>
        <attr name="halfLowStar" format="reference"/>
        <attr name="halfOverStar" format="reference"/>
        <attr name="spaceBetween" format="dimension"/>
    </declare-styleable>

好了,就這么簡單

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末狸捕,一起剝皮案震驚了整個濱河市喷鸽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌灸拍,老刑警劉巖做祝,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異鸡岗,居然都是意外死亡混槐,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門轩性,熙熙樓的掌柜王于貴愁眉苦臉地迎上來纵隔,“玉大人,你說我怎么就攤上這事炮姨“乒危” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵舒岸,是天一觀的道長绅作。 經(jīng)常有香客問我,道長蛾派,這世上最難降的妖魔是什么俄认? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮洪乍,結(jié)果婚禮上眯杏,老公的妹妹穿的比我還像新娘。我一直安慰自己壳澳,他們只是感情好岂贩,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著巷波,像睡著了一般萎津。 火紅的嫁衣襯著肌膚如雪卸伞。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天锉屈,我揣著相機與錄音荤傲,去河邊找鬼。 笑死颈渊,一個胖子當著我的面吹牛遂黍,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播俊嗽,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼妓湘,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了乌询?” 一聲冷哼從身側(cè)響起榜贴,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎妹田,沒想到半個月后唬党,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡鬼佣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年驶拱,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片晶衷。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡蓝纲,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出晌纫,到底是詐尸還是另有隱情税迷,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布锹漱,位于F島的核電站箭养,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏哥牍。R本人自食惡果不足惜毕泌,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望嗅辣。 院中可真熱鬧撼泛,春花似錦、人聲如沸澡谭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至抠忘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間外永,已是汗流浹背崎脉。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留伯顶,地道東北人囚灼。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像祭衩,于是被迫代替她去往敵國和親灶体。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,167評論 25 707
  • 發(fā)現(xiàn) 關注 消息 iOS 第三方庫掐暮、插件蝎抽、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,105評論 4 62
  • 她性格多面精算,因為經(jīng)歷復雜瓢宦,整個人潛伏著許多弱點和缺陷。 他是聰明睿智型的灰羽,認識他之前驮履,她在眾人眼里也還算是聰慧,也...
    萱小蕾閱讀 436評論 0 0
  • 影響自我連接的因素有: 1對自己的感受有評判:我不應該生氣廉嚼。我不能太懦弱玫镐,應該像個男人,堅強點怠噪。 2對自己的恐懼 ...
    微笑鹿友閱讀 447評論 0 1
  • 你有沒有過這樣的經(jīng)歷摘悴?上課的時候認真聽講認真做筆記,可知識點在腦子里還是漿糊一樣的存在舰绘□逵鳎或者你上課時聽明白...
    北野荷閱讀 812評論 0 1