前言
在開發中,經常會遇到SeekBar元件的開發,一個高效的自定義SeekBar顯得尤為重要,筆者剛好也在項目中大量使用帶有數字的拖拽進度條,在深思熟慮後,打算從繼承源碼形式上,把數字繪制在拖拽進度條上,讓拖拽的時候時刻去更新數字。這種實作方式不到100行代碼,代碼極其精簡,功能極其好用,另外,這種方案可以用于各種元件繪制在進度條上方,這塊的實作就看需求的具體效果
本例子中高仿抖音的進度拖拽效果,實作效果如下
實作思路
- 繼承SeekBar,自定義屬性
- 在onDraw方法增加數字的繪制和數字陰影的繪制
實作分析
1、快速使用
在xml直接使用,其監聽進度變化同SeekBar元件
<com.baseui.seekbar.NumberSeekBar
android:layout_width="match_parent"
android:layout_height="54dp"
android:max="100"
android:paddingStart="24dp"
android:paddingEnd="24dp"
android:progressDrawable="@drawable/progress_seek_bar_beauty"
android:thumb="@drawable/icon_beauty_seek_bar_thumb"
app:textColor="@color/white"
app:textMarginBottom="2dp"
app:textShadowColor="#80000000"
app:textShadowOffsetX="0dp"
app:textShadowOffsetY="0dp"
app:textShadowRadius="2dp"
app:textSize="12sp"
app:withText="true"
app:withTextShadow="true"
tools:progress="50"/>
2、自定義屬性
在attr中增加自定義的屬性
<resources>
<declare-styleable name="InheritedSeekBar">
<attr name="withText" format="boolean" />
<attr name="textSize" format="dimension" />
<attr name="textColor" format="color" />
<attr name="textMarginBottom" format="dimension" />
<attr name="withTextShadow" format="boolean" />
<attr name="textShadowColor" format="color" />
<attr name="textShadowOffsetX" format="dimension" />
<attr name="textShadowOffsetY" format="dimension" />
<attr name="textShadowRadius" format="dimension" />
</declare-styleable>
</resources>
- withText:是否帶有進度值
- textSize:進度值的大小
- textColor:進度值的顔色
- textMarginBottom:進度值底邊距
- withTextShadow:是否帶有進度值的陰影
- textShadowColor:進度值陰影的顔色
- textShadowOffsetX:進度值陰影的x坐标偏移
- textShadowOffsetY:進度值陰影的y坐标偏移
- textShadowRadius:進度值陰影的圓角
3、擷取屬性
通過
attributeSet
擷取自定義屬性,同時擷取進度的屬性和進度陰影的屬性
class NumberSeekBar @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : AppCompatSeekBar(context, attrs, defStyleAttr) {
private val textPaint = Paint()
private var withText: Boolean = false
private var textSize: Float = 0f
private var textColor: Int = Color.BLACK
private var textMarginBottom: Int = 0
private var withTextShadow = false
private var textShadowColor = Color.BLACK
private var textShadowRadius = 0
private var textShadowOffsetX = 0
private var textShadowOffsetY = 0
init {
init(context, attrs)
}
private fun init(context: Context, attributeSet: AttributeSet?) {
val a: TypedArray = context.obtainStyledAttributes(attributeSet, R.styleable.InheritedSeekBar)
// 擷取進度的屬性
withText = a.getBoolean(R.styleable.InheritedSeekBar_withText, false)
if (withText) {
textSize = a.getDimensionPixelSize(R.styleable.InheritedSeekBar_textSize,
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
12f,
context.resources.displayMetrics).toInt()).toFloat()
textColor = a.getColor(R.styleable.InheritedSeekBar_textColor, textColor)
textMarginBottom = a.getDimensionPixelSize(R.styleable.InheritedSeekBar_textMarginBottom, 0)
}
// 擷取進度陰影的屬性
withTextShadow = a.getBoolean(R.styleable.InheritedSeekBar_withTextShadow, false)
if (withTextShadow) {
textShadowColor = a.getColor(R.styleable.InheritedSeekBar_textShadowColor, textShadowColor)
textShadowRadius = a.getDimensionPixelSize(R.styleable.InheritedSeekBar_textShadowRadius, 0)
textShadowOffsetX = a.getDimensionPixelOffset(R.styleable.InheritedSeekBar_textShadowOffsetX, 0)
textShadowOffsetY = a.getDimensionPixelOffset(R.styleable.InheritedSeekBar_textShadowOffsetY, 0)
}
a.recycle()
// 對畫筆設定值和陰影
if (withText) {
textPaint.textSize = textSize
textPaint.color = textColor
textPaint.textAlign = Paint.Align.CENTER
}
if (withTextShadow) {
textPaint.setShadowLayer(textShadowRadius.toFloat(), textShadowOffsetX.toFloat(),
textShadowOffsetY.toFloat(), textShadowColor)
}
}
}
4、繪制數字和陰影
通過複寫
onDraw
方法,經過計算偏移量後,在進度拖拽的上方繪制數字
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
if (withText) {
drawText(canvas)
}
}
private fun drawText(canvas: Canvas) {
val saveCount = canvas.save()
val thumbTopY = thumb.bounds.top
// 計算拖拽元件的中點
val thumbCenterX = paddingStart + progress.toFloat() / max * (width - paddingStart - paddingEnd)
canvas.drawText(progress.toString(), thumbCenterX, thumbTopY.toFloat() - textMarginBottom, textPaint)
canvas.restoreToCount(saveCount)
}
5、進度條顔色
對于進度條顔色是
layer-list
,可以設定進度的背景和進度顔色值,而進度拖拽元件,其實就是個圓形的Icon圖檔而已
android:progressDrawable="@drawable/progress_seek_bar"
android:thumb="@drawable/icon_beauty_seek_bar_thumb"
在
progress_seek_bar
設定進度成黃色,背景成少許透明的灰黑色
<?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">
<shape>
<solid android:color="#29ffffff" />
<corners android:radius="3dp" />
<size android:height="3dp" />
</shape>
</item>
<item
android:id="@android:id/secondaryProgress"
android:gravity="center_vertical">
<clip>
<shape>
<solid android:color="#29ffffff" />
<corners android:radius="3dp" />
<size android:height="3dp" />
</shape>
</clip>
</item>
<item
android:id="@android:id/progress"
android:gravity="center_vertical">
<clip>
<shape>
<solid android:color="#ffffe000" />
<corners android:radius="3dp" />
<size android:height="3dp" />
</shape>
</clip>
</item>
</layer-list>