美文网首页Android自定义View
自定义 view 练手 - 自定义 ratingBar

自定义 view 练手 - 自定义 ratingBar

作者: 前行的乌龟 | 来源:发表于2018-10-26 17:47 被阅读23次

话说我们终于来到了真正的自定义 view 环节了,用 canvas 来绘制我们想要的一切了。开始嘛,总要有点不一样的,咱们的开始从 自定义 ratingBar 开始,系统的 ratingBar 那是一个蛋星星疼啊,不能调整星星大小,要是替换星星图片资源的话,还容易出问题,不是星星显示不全就是下面长脚了 ~

所以 自定义 ratingBar 是非常有显示意义的,ratingBar 说难不难,说简单也不简单,对于初学者练手及其具有重要意义,通过 自定义 ratingBar 我们可以熟悉 自定义 view 中所有的代码细节,写完我们自己的 ratingBar 后,自定义 view 对于我们来说就不算陌生了。

这是我写的:


ezgif.com-video-to-gif.gif

第一个星星的黑框不要在意,只是表示图片的尺寸范围,项目种已经去掉了。这个 ratingBar 打磨的差不多了,大家可以直接复制过去用滴 ~

项目地址:BW_Libs

我用的是矢量图,矢量图在 4.x 上的兼容太是个问题了,具体请看:

项目思路


ratingBar 的思路并不难,就是根据数量画星星,星星一般都是图片,区别是 png 还是矢量图,当然也可以不用图全程用 path 画,但是我是没找到画星星的 paht 路径出来,有心无力啊

我这里的 ratingBar 星星可以调节大小,默认我给了个 24dp,大家在使用时高自适应就行,高根据设置的星星大小走,为了图省事,星星都是正方形的哦

自定义参数没几个,如下:

    <declare-styleable name="MyRatingBar">
        <!--星星间距-->
        <attr name="starStep" format="dimension"/>
        <!--星星大小-->
        <attr name="starSize" format="dimension"/>
        <!--当前星星个数-->
        <attr name="currentStarCount" format="float"/>
        <!-- 最大星星个数-->
        <attr name="maxStarCount" format="integer"/>
        <!--星星选中图-->
        <attr name="drawable_select" format="reference"/>
        <!--星星半选中图-->
        <attr name="drawable_halfSelect" format="reference"/>
        <!--星星未选中图-->
        <attr name="drawable_unSelect" format="reference"/>
        <!--是或可以触摸-->
        <attr name="canTouch" format="boolean"/>
    </declare-styleable>

基本仿照系统原生的 ratingbar ,但是添加了星星尺寸和间距。图片方面因为要支持半星所以有3种图:全星,半星,没星

绘制上也是简单的很,canvas 每绘制一张图,canvas 位移指定宽度

selectDrawable.draw(canvas)
canvas?.translate((startSize + startSetp).toFloat(), 0f)

ratingBar 中最有难度的就是区分星星是全的还是半的还是没有的了,我是利用一个集合存储每个星星的显示状态,根据设置的评分数,计算全星,半星,没星的分界点,我这里主要有小数就算半星

对评分数取整,评分数要是大于取整的数,那说明有小数,就有半星,那么分界点就是这个取整之后的整数了,然后往星星显示状态的集合里写入相应个数的数据就行

    fun cauculateStartState() {

        startInfoList.clear()

        if (currentStartCount == 0f) {
            (1..maxStartCount).forEach { startInfoList.add(STATE_UNSELECT) }
            return
        }

        var index: Int = currentStartCount.toInt()
        if (index >= 1) (1..index).forEach { startInfoList.add(STATE_SELECT) }

        // 说明有小数位
        if (currentStartCount > index) {
            startInfoList.add(STATE_HALF)
            index += 2
        } else {
            index++
        }

        if (maxStartCount >= index) {
            (index..maxStartCount).forEach { startInfoList.add(STATE_UNSELECT) }
        }
    }

触摸的话也不难,用触摸点的 x 坐标 / 星星大小+分割大小,分析得到 float 值,根据小数位范围判断是全星还是半星

    override fun onTouchEvent(event: MotionEvent?): Boolean {

        if (!canTouch) return false

        if (event?.action == MotionEvent.ACTION_DOWN) {

            if (event.x >= width) {
                setRating(maxStartCount.toFloat())
                return true
            }

            var index_float: Float = event.x / (startSize + startSetp)
            var index_int: Int = index_float.toInt()

            if (index_float <= (index_int + 0.3f)) {
                setRating(index_int.toFloat())
                return true
            }

            if (index_float > (index_int + 0.3f) && index_float < (index_int + 0.7f)) {
                setRating(index_int + 0.5f)
                return true
            }

            if (index_float >= (index_int + 0.7f)) {
                setRating((index_int + 1).toFloat())
                return true
            }
        }

        return true
    }

相关文章

网友评论

    本文标题:自定义 view 练手 - 自定义 ratingBar

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