美文网首页我爱编程
Kotlin实现自定义RatingBar

Kotlin实现自定义RatingBar

作者: kksoCoud | 来源:发表于2018-05-26 23:13 被阅读61次

好久没分享过了,突然感觉手都有点生疏了。最近需求ratingbar显示规则为:0为空星,1为全星,0.5为半星,小于0.5为小半星,大于0.5则为大半星。对于这个需求第一感觉就是使用系统自带RatingBar,但在使用过程中发现其只能实现空星、半星、全星,其所自带的android:stepSize=""android:rating=""属性并不能很好的实现此种需求效果,并且网上实现的自定义Ratingbar,基本都是通过继承LinearLayout,内部创建ImageView来实现的,个人感觉这样实现不是特别好,于是决定自己动手丰衣足食。
基本思路是:通过继承View完全自定来实现(onMeasure、onDraw来手动测绘)。好了,bibi了这么多,还是先看效果图吧。

custom_rating_bar.png

效果就是如上,基本需求已经满足了,嘿嘿。
下面我们来看看它的实现过程吧,基本就是撸代码啦。。。

//空星
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
//默认星星个数
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()
        }

    //星星总数
    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)
            }
        }
    }

    /**
     * 获取进度全星个数
     */
    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>

好了,就这么简单

相关文章

网友评论

    本文标题:Kotlin实现自定义RatingBar

    本文链接:https://www.haomeiwen.com/subject/rnevjftx.html