最近搬砖,嗯。
有一个seekbar,然后呢需要在thumb下面显示一个进度百分百的文字。然后样式和系统的长的不一样。所以需要简单处理下。
参考资料
正文
思路就那么几种,一种是基于seekbar,设置style,属性啥的。一种是自定义view啥都手写,最后一种就是继承seekbar,用他的逻辑,然后自己画。道理就很简单,自己整就行。
设置style或属性
首先定义xml:
ini
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@android:id/background"
android:gravity="center_vertical|fill_horizontal">
<shape android:shape="rectangle">
<size android:height="10dp" />
<solid android:color="#282b31" />
<corners android:radius="10dp" />
</shape>
</item>
<item
android:id="@android:id/progress"
android:gravity="center_vertical|fill_horizontal">
<scale android:scaleWidth="100%">
<shape android:shape="rectangle">
<size android:height="10dp" />
<gradient
android:angle="0"
android:endColor="#aab8d4"
android:startColor="#707d93" />
<corners android:radius="10dp" />
</shape>
</scale>
</item>
<item android:id="@android:id/secondaryProgress" android:gravity="center_vertical|fill_horizontal">
<shape android:shape="rectangle">
<size android:height="10dp" />
<solid android:color="#282b31" />
<corners android:radius="10dp" />
</shape>
</item>
</layer-list>
定义了几个id:
- @android:id/background 进度条的背景。
- @android:id/progress 这个玩意是进度条。
- @android:id/secondaryProgress 缓冲进度。
借用一张图(上面blog中tou的,感觉很完美的契合了):
通过这张图,我们就非常直观的了解到了。整个seekbar 的绘制元素。
最后就是设置thumb,这个肯定不能是SVG。thumb 也有样式。
xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 按下状态 -->
<item android:drawable="@drawable/shape_seekbar_btn" android:state_pressed="true" />
<!-- 焦点状态 -->
<item android:drawable="@drawable/shape_seekbar_btn" android:state_focused="true" />
<!-- 选择状态 -->
<item android:drawable="@drawable/shape_seekbar_btn" android:state_selected="true" />
<!-- 默认状态 -->
<item android:drawable="@drawable/shape_seekbar_btn" />
</selector>
OK,这么一套下来。剩下的就是监听seek,然后设置文本了。
基于继承AppCompatSeekBar的自定义
因为某些原因(不知道到thumb不能设置svg,至于为啥不能,还没有细看),当时搞切图的时候,把thumb导成svg了,做的时候又发现搞切图的平台打不开了。算了,反正都需要自定义,那就thumb 我也自己画,反正设置的svg 不显示。
绘制thumb和文本
我们需求很简单,对thumb也没有啥状态,就一直那个样式。即然我都导svg了,这path我非用不可了好吧。我们通过:
arduino
PathParser.createPathFromPathData("path")
这么就获取到了一个path对象。有一个问题,那就是path 对象创建成功后,就没法设置开始位置了,我们thumb总不能一直卡在某个角落吧,但是,山不转水转,我canvas自己动不行吗?
- canvas.translate() 平移
- Matrix().postTranslate()也可以平移,canvas.setMatrix()
移动canvas有一个好处,那就是绘制文本的时候,不需要计算文本在x 轴的位置了,thumb绘制的时候已经平移了,一箭双雕,完美。剩下的就简单了,通过canvas.drawPath()和drawText() 即可。
绘制圆角矩形
当thumb 自己画的时候,已经走远了好吧。不同的手机跑出来thumb和进度条没有一个水平线上。OK,为了技术(填坑),进度和背景我也自己画。圆角矩形的path:
scss
val path by lazy {
Path().apply {
val rectF = RectF(
0f,
0f,
width ,
height
)
val radius = SizeUtils.dp2px(8f).toFloat()
addRoundRect(
rectF,
radius, radius,
Path.Direction.CW
)
}
}
seekbar 的进度和背景的区域就在rectf 中的right知不一样,但是不能用by lazy.所以通过函数返回即可。即然都自己画了,所以onDraw 中的supper就不需要了。
设置监听
这个就很简单了,就是在setOnSeekBarChangeListener于onProgressChanged函数中,调用invalidate()刷新绘制即可。
基于view自定义
我们上面基于seekbar 已经处理了绘制相关的逻辑了,基于view的自定义基本上就是基于onTouchEvent 分发event事件了。
- ACTION_DOWN 按下的时候,如果需求上是可以点击切换的的话,就不拦截,点哪里然后通过x或者y计算一个进度值,如果不支持点击切换,那么需要判断触摸区域是否是thumb所在区域。
- ACTION_MOVE 移动也是一个道理,每次移动一定的量的时候触发一次刷新,或者每次移动都重新计算进度刷新。
- ACTION_UP 抬起的时候,也更新进度,当然可以更新。
总结
整体来说,还是蛮简单的,当然留下了一个坑为什么VectorDrawable 通过.draw(canvas) 绘制不出来还没有看,同时canvas 绘制 svg的bitmap 和drawable 好像都不行。
作为2024年第一篇水文,每天留一点坑,年终总结的时候就会发现要填的太多了。