话说我们终于来到了真正的自定义 view 环节了,用 canvas 来绘制我们想要的一切了。开始嘛,总要有点不一样的,咱们的开始从 自定义 ratingBar 开始,系统的 ratingBar 那是一个蛋星星疼啊,不能调整星星大小,要是替换星星图片资源的话,还容易出问题,不是星星显示不全就是下面长脚了 ~
所以 自定义 ratingBar 是非常有显示意义的,ratingBar 说难不难,说简单也不简单,对于初学者练手及其具有重要意义,通过 自定义 ratingBar 我们可以熟悉 自定义 view 中所有的代码细节,写完我们自己的 ratingBar 后,自定义 view 对于我们来说就不算陌生了。
这是我写的:
![](https://img.haomeiwen.com/i1785445/0e56be3a6c003f76.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
}
网友评论