效果图


自定义view代码
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.View
import androidx.annotation.Nullable
import com.bkex.common.utils.LogUtils
//环形进度条
class PlayPregressBar(
context: Context,
@Nullable attrs: AttributeSet,
defStyleAttr: Int,
defStyleRes: Int
) :
View(context, attrs, defStyleAttr, defStyleRes) {
constructor(context: Context, @Nullable attrs: AttributeSet, defStyleAttr: Int) : this(
context,
attrs,
defStyleAttr,
0
)
constructor(context: Context, @Nullable attrs: AttributeSet) : this(context, attrs, 0, 0)
val TAG = "PlayPregressBar"
var colorPuse: String = "#E62020"//暂停图标颜色
var colorPlay: String = "#808080"//播放图片颜色
var colorCricle: String = "#808080"//外环颜色
var colorProgress: String = "#E62020"//已经走过的进度颜色
var r_c = 0f//圆环半径
var paintPause: Paint//暂停图标画笔
var paintPlay: Paint//播放图标画笔
var paintCricle: Paint//圆环画笔
var paintProgress: Paint//已经走过的图标画笔
var w = 0//view的宽
var h = 0//wiew的高
var ox = 0f//圆心坐标x
var oy = 0f//圆心y
var painWidth = 2f//画笔宽
var proportion = 0.65f//图形占比,圆占view的宽度(高度,按较小的计算)比,该数值越大图片占view的比例就越大
var max: Int = 100
var progress: Int = 0
set(value) {
field = value
invalidate()
}
var isPlaying = false
set(value) {
field = value
invalidate()
}
//播放图标三个点的坐标
val playIconArray: Array<Coordinate> by lazy {
arrayOf(Coordinate(), Coordinate(), Coordinate())
}
val pauseIconArray: Array<Coordinate> by lazy {
arrayOf(Coordinate(), Coordinate(), Coordinate(), Coordinate())
}
val progressArray: Array<Coordinate> by lazy {
arrayOf(Coordinate(), Coordinate())
}
init {
paintPause = Paint().apply {
isAntiAlias = true
style = Paint.Style.STROKE//空心,FILL填充
color = Color.parseColor(colorPuse)
strokeWidth = painWidth
}
paintPlay = Paint().apply {
isAntiAlias = true
style = Paint.Style.STROKE//空心,FILL填充
color = Color.parseColor(colorPlay)
strokeWidth = painWidth
}
paintCricle = Paint().apply {
isAntiAlias = true
style = Paint.Style.STROKE//空心,FILL填充
color = Color.parseColor(colorCricle)
strokeWidth = painWidth
}
paintProgress = Paint().apply {
isAntiAlias = true
style = Paint.Style.STROKE//空心,FILL填充
color = Color.parseColor(colorProgress)
strokeWidth = painWidth + 2
}
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
LogUtils.i(
TAG,
Throwable(),
"changed=$changed,left=$left,top=$top,right=$right,bottom=$bottom,"
)
//获取view宽高
h = bottom - top
w = right - left
//计算圆心坐标和宽高,view内相对坐标
ox = w * 0.5f
oy = h * 0.5f
if (w > h) {
r_c = h * proportion * 0.5f
} else {
r_c = w * proportion * 0.5f
}
LogUtils.i(TAG, Throwable(), "h=$h,w=$w,x_c=$ox,y_c=$oy,r_c=$r_c,")
// LogUtils.i(TAG, Throwable(), "sqrt=" + Math.sqrt(4.0))
//计算三角形位置坐标
// 3:4/5
// 13.2:17.6/22
var rMin = r_c * 0.5f
var temp = 3 * rMin / (2 * Math.sqrt(3.0))
playIconArray[0].cx = (ox - Math.sqrt(rMin * rMin - temp * temp)).toFloat()
playIconArray[0].cy = (oy - temp).toFloat()
playIconArray[1].cx = playIconArray[0].cx
playIconArray[1].cy = (oy + temp).toFloat()
playIconArray[2].cx = ox + rMin
playIconArray[2].cy = oy
LogUtils.i(TAG, Throwable(), "x1=" + playIconArray[0].cx + ",y1=" + playIconArray[0].cy)
LogUtils.i(TAG, Throwable(), "x2=" + playIconArray[1].cx + ",y2=" + playIconArray[1].cy)
LogUtils.i(TAG, Throwable(), "x3=" + playIconArray[2].cx + ",y3=" + playIconArray[2].cy)
//计算暂停双竖线的坐标
var temp2 = 0.25f * r_c
var tempH = 0.35f * r_c
pauseIconArray[0].cx = ox - temp2
pauseIconArray[0].cy = oy - tempH
pauseIconArray[1].cx = pauseIconArray[0].cx
pauseIconArray[1].cy = oy + tempH
pauseIconArray[2].cx = ox + temp2
pauseIconArray[2].cy = pauseIconArray[0].cy
pauseIconArray[3].cx = pauseIconArray[2].cx
pauseIconArray[3].cy = pauseIconArray[1].cy
//圆弧所在矩形坐标
progressArray[0].cx = ox - r_c
progressArray[0].cy = oy - r_c
progressArray[1].cx = ox + r_c
progressArray[1].cy = oy + r_c
// progressArray[0].cx = ox - r_c-1
// progressArray[0].cy = oy - r_c-1
// progressArray[1].cx = ox + r_c+1
// progressArray[1].cy = oy + r_c+1
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
LogUtils.i(TAG, Throwable(), "onDraw:progress=$progress")
//画外层圆圈
canvas?.drawCircle(ox, oy, r_c, paintCricle)
// canvas?.drawCircle(ox, oy, 22f, paintCricle)
if (isPlaying) {
//画暂停双竖线
var path1 = Path()
path1.moveTo(pauseIconArray[0].cx, pauseIconArray[0].cy)
path1.lineTo(pauseIconArray[1].cx, pauseIconArray[1].cy)
path1.moveTo(pauseIconArray[2].cx, pauseIconArray[2].cy)
path1.lineTo(pauseIconArray[3].cx, pauseIconArray[3].cy)
path1.close()
canvas?.drawPath(path1, paintPause)
} else {
//画内层正三角形
var path = Path()
path.moveTo(playIconArray[0].cx, playIconArray[0].cy)
path.lineTo(playIconArray[1].cx, playIconArray[1].cy)
path.lineTo(playIconArray[2].cx, playIconArray[2].cy)
path.lineTo(playIconArray[0].cx, playIconArray[0].cy)
path.close()
canvas?.drawPath(path, paintPlay)
}
// RectF rect = new RectF(10, 10, 300, 400);
//// canvas.drawArc(rect, 参数一是RectF对象,一个矩形区域椭圆形的限用于定义在形状、大小、电弧
// 180, 参数二是起始角(度)在电弧的开始
// 180, 参数三扫描角(度)开始顺时针测量的
// true, 参数四是如果这是真的话,包括椭圆中心的电弧,并关闭它,如果它是假这将是一个弧线,参数五是Paint对象;
// mPaint);
//画进度弧线
var rect = RectF(
progressArray[0].cx, progressArray[0].cy, progressArray[1].cx, progressArray[1].cy
)
canvas?.drawArc(rect, -90f, 360f * progress / max, false, paintProgress)
}
data class Coordinate(var cx: Float = 0f, var cy: Float = 0f) {
}
}
使用代码
<com.zbb.mine.widget.PlayPregressBar
android:id="@+id/ppbPlayOrPause"
android:layout_width="42dp"
android:layout_height="0dp"
android:onClick="@{()->controllerViewModel.playOrPause()}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toLeftOf="@id/ivMenuGroup"
app:layout_constraintTop_toTopOf="parent" />
控制代码
fun iniViewModel2(){
controllerViewModel.musicEntity.observe(this, Observer {
if(it!=null){
LogUtils.i(TAG, Throwable(),"it.duration="+it.duration)
//设置进度条最大长度
binding2.include.ppbPlayOrPause.max=it.duration
}
})
controllerViewModel.progress.observe(this, Observer {
//设置进度条进度
binding2.include.ppbPlayOrPause.progress=it
})
controllerViewModel.isPlaying.observe(this, Observer {
//改变播放状态
binding2.include.ppbPlayOrPause.isPlaying=it
})
controllerViewModel.init()
}
网友评论