美文网首页
带环形进度条的播放暂停自定义view(纯手工)

带环形进度条的播放暂停自定义view(纯手工)

作者: 御坂七十一号 | 来源:发表于2020-09-17 13:47 被阅读0次

效果图


image.png
image.png

自定义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()
    }

相关文章

网友评论

      本文标题:带环形进度条的播放暂停自定义view(纯手工)

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