Android视频播放暂停动效的按钮

发布于:2024-06-15 ⋅ 阅读:(118) ⋅ 点赞:(0)

上来直接给大家搂代码

 

class PlayButton @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
    View(context, attrs, defStyleAttr) {

    companion object {

        /** 播放状态 */
        const val STATE_PLAY: Int = 0

        /** 暂停状态 */
        const val STATE_PAUSE: Int = 1
    }

    /** 当前状态 */
    private var currentState: Int = STATE_PAUSE

    /** 动画时间 */
    private var animDuration: Int

    private val paint: Paint
    private var viewWidth: Int = 0
    private var viewHeight: Int = 0
    private var centerX: Int = 0
    private var centerY: Int = 0
    private var circleRadius: Int = 0
    private var rectF: RectF? = null
    private var bgRectF: RectF? = null
    private var fraction: Float = 1f
    private val path: Path
    private val dstPath: Path
    private val pathMeasure: PathMeasure
    private var pathLength: Float = 0f

    init {
        val typedArray: TypedArray = context.obtainStyledAttributes(attrs, R.styleable.PlayButton)
        val lineColor: Int = typedArray.getColor(R.styleable.PlayButton_pb_lineColor, Color.WHITE)
        val lineSize: Int = typedArray.getInteger(
            R.styleable.PlayButton_pb_lineSize,
            resources.getDimension(R.dimen.dp_4).toInt()
        )
        animDuration = typedArray.getInteger(R.styleable.PlayButton_pb_animDuration, 200)
        typedArray.recycle()

        // 关闭硬件加速
        setLayerType(LAYER_TYPE_SOFTWARE, null)
        paint = Paint(Paint.ANTI_ALIAS_FLAG)
        paint.style = Paint.Style.STROKE
        paint.strokeCap = Paint.Cap.ROUND
        paint.color = lineColor
        paint.strokeWidth = lineSize.toFloat()
        paint.pathEffect = CornerPathEffect(1f)
        path = Path()
        dstPath = Path()
        pathMeasure = PathMeasure()
    }

    override fun onSizeChanged(width: Int, height: Int, oldWidth: Int, oldHeight: Int) {
        super.onSizeChanged(width, height, oldWidth, oldHeight)
        viewWidth = width * 9 / 10
        viewHeight = height * 9 / 10
        circleRadius = width / resources.getDimension(R.dimen.dp_4).toInt()
        centerX = width / 2
        centerY = height / 2
        rectF = RectF(
            (centerX - circleRadius).toFloat(), centerY + 0.6f * circleRadius,
            (centerX + circleRadius).toFloat(), centerY + 2.6f * circleRadius
        )
        bgRectF = RectF(
            centerX - viewWidth / 2f, centerY - viewHeight / 2f,
            centerX + viewWidth / 2f, centerY + viewHeight / 2f
        )
        path.moveTo((centerX - circleRadius).toFloat(), centerY + 1.8f * circleRadius)
        path.lineTo((centerX - circleRadius).toFloat(), centerY - 1.8f * circleRadius)
        path.lineTo((centerX + circleRadius).toFloat(), centerY.toFloat())
        path.close()
        pathMeasure.setPath(path, false)
        pathLength = pathMeasure.length
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        var finalWidthMeasureSpec: Int = widthMeasureSpec
        var finalHeightMeasureSpec: Int = heightMeasureSpec
        when (MeasureSpec.getMode(finalWidthMeasureSpec)) {
            MeasureSpec.AT_MOST, MeasureSpec.UNSPECIFIED ->
                finalWidthMeasureSpec = MeasureSpec.makeMeasureSpec(resources.getDimension(R.dimen.dp_60).toInt(), MeasureSpec.EXACTLY)
            MeasureSpec.EXACTLY -> {}
        }
        when (MeasureSpec.getMode(finalHeightMeasureSpec)) {
            MeasureSpec.AT_MOST, MeasureSpec.UNSPECIFIED ->
                finalHeightMeasureSpec = MeasureSpec.makeMeasureSpec(resources.getDimension(R.dimen.dp_60).toInt(), MeasureSpec.EXACTLY)
            MeasureSpec.EXACTLY -> {}
        }
        setMeasuredDimension(finalWidthMeasureSpec, finalHeightMeasureSpec)
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        canvas.drawCircle(centerX.toFloat(), centerY.toFloat(), viewWidth / 2f, paint)
        when {
            fraction < 0 -> {
                // 弹性部分
                canvas.drawLine((centerX + circleRadius).toFloat(),
                    centerY - 1.6f * circleRadius + 10 * circleRadius * fraction, (centerX + circleRadius).toFloat(),
                    centerY + (1.6f * circleRadius) + (10 * circleRadius * fraction), paint)
                canvas.drawLine((centerX - circleRadius).toFloat(), centerY - 1.6f * circleRadius, (
                            centerX - circleRadius).toFloat(), centerY + 1.6f * circleRadius, paint)
                canvas.drawArc(bgRectF!!, -105f, 360f, false, paint)
            }
            fraction <= 0.3 -> {
                // 右侧直线和下方曲线
                canvas.drawLine((centerX + circleRadius).toFloat(),
                    centerY - 1.6f * circleRadius + circleRadius * 3.2f / 0.3f * fraction, (centerX + circleRadius).toFloat(),
                    centerY + 1.6f * circleRadius, paint)
                canvas.drawLine((centerX - circleRadius).toFloat(), centerY - 1.6f * circleRadius, (
                            centerX - circleRadius).toFloat(), centerY + 1.6f * circleRadius, paint)
                if (fraction != 0f) {
                    canvas.drawArc(rectF!!, 0f, 180f / 0.3f * fraction, false, paint)
                }
                canvas.drawArc(bgRectF!!, -105 + 360 * fraction, 360 * (1 - fraction), false, paint)
            }
            fraction <= 0.6 -> {
                // 下方曲线和三角形
                canvas.drawArc(rectF!!, 180f / 0.3f * (fraction - 0.3f),
                    180 - 180f / 0.3f * (fraction - 0.3f), false, paint)
                dstPath.reset()
                pathMeasure.getSegment(0.02f * pathLength,
                    0.38f * pathLength + 0.42f * pathLength / 0.3f * (fraction - 0.3f),
                    dstPath, true)
                canvas.drawPath(dstPath, paint)
                canvas.drawArc(bgRectF!!, -105 + 360 * fraction, 360 * (1 - fraction), false, paint)
            }
            fraction <= 0.8 -> {
                // 三角形
                dstPath.reset()
                pathMeasure.getSegment(0.02f * pathLength + 0.2f * pathLength / 0.2f * (fraction - 0.6f),
                    0.8f * pathLength + 0.2f * pathLength / 0.2f * (fraction - 0.6f), dstPath, true)
                canvas.drawPath(dstPath, paint)
                canvas.drawArc(bgRectF!!, -105 + 360 * fraction, 360 * (1 - fraction), false, paint)
            }
            else -> {
                // 弹性部分
                dstPath.reset()
                pathMeasure.getSegment(10 * circleRadius * (fraction - 1), pathLength, dstPath, true)
                canvas.drawPath(dstPath, paint)
            }
        }
    }

    /**
     * 播放状态
     */
    fun play() {
        if (currentState == STATE_PLAY) {
            return
        }
        currentState = STATE_PLAY
        val valueAnimator: ValueAnimator = ValueAnimator.ofFloat(1f, 100f)
        valueAnimator.duration = animDuration.toLong()
        valueAnimator.interpolator = AnticipateInterpolator()
        valueAnimator.addUpdateListener { animation: ValueAnimator ->
            fraction = 1 - animation.animatedFraction
            invalidate()
        }
        valueAnimator.start()
    }

    /**
     * 暂停状态
     */
    fun pause() {
        if (currentState == STATE_PAUSE) {
            return
        }
        currentState = STATE_PAUSE
        val valueAnimator: ValueAnimator = ValueAnimator.ofFloat(1f, 100f)
        valueAnimator.duration = animDuration.toLong()
        valueAnimator.interpolator = AnticipateInterpolator()
        valueAnimator.addUpdateListener { animation: ValueAnimator ->
            fraction = animation.animatedFraction
            invalidate()
        }
        valueAnimator.start()
    }

    /**
     * 获取当前状态
     */
    fun getCurrentState(): Int {
        return currentState
    }

    /**
     * 设置动画时间
     */
    fun setAnimDuration(duration: Int) {
        animDuration = duration
    }

    /**
     * 设置线条颜色
     */
    fun setLineColor(color: Int) {
        paint.color = color
        invalidate()
    }

    /**
     * 设置线条大小
     */
    fun setLineSize(size: Int) {
        paint.strokeWidth = size.toFloat()
        invalidate()
    }
}

xml给大家也展示下,图片的话暂不上传了,自己替换

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/black"
    android:orientation="vertical">

    <VideoView
        android:id="@+id/vv_player_view_video"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center"
        android:keepScreenOn="true" />

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        android:orientation="vertical">

        <com.hjq.shape.layout.ShapeFrameLayout
            android:id="@+id/ll_player_view_top"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="top"
            android:orientation="horizontal"
            android:visibility="invisible"
            app:shape="rectangle"
            app:shape_angle="270"
            app:shape_centerColor="@color/black20"
            app:shape_endColor="@color/transparent"
            app:shape_startColor="#AA000000"
            tools:visibility="visible">

            <androidx.appcompat.widget.AppCompatImageView
                android:id="@+id/iv_player_view_left"
                android:layout_width="@dimen/dp_50"
                android:layout_height="@dimen/dp_50"
                android:layout_gravity="center_vertical"
                android:padding="@dimen/dp_10"
                android:visibility="invisible"
                app:srcCompat="@drawable/arrows_left_ic"
                app:tint="@color/white"
                tools:visibility="visible" />

            <androidx.appcompat.widget.AppCompatTextView
                android:id="@+id/tv_player_view_title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:layout_marginHorizontal="@dimen/dp_50"
                android:ellipsize="marquee"
                android:gravity="center_horizontal"
                android:singleLine="true"
                android:textColor="@color/white"
                android:textSize="@dimen/sp_17"
                tools:text="我是视频标题" />

        </com.hjq.shape.layout.ShapeFrameLayout>

        <com.hjq.widget.view.PlayButton
            android:id="@+id/iv_player_view_control"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:visibility="invisible"
            tools:visibility="visible" />

        <com.hjq.shape.view.ShapeImageView
            android:id="@+id/iv_player_view_lock"
            android:layout_width="@dimen/dp_45"
            android:layout_height="@dimen/dp_45"
            android:layout_gravity="start|center_vertical"
            android:layout_marginStart="@dimen/dp_5"
            android:padding="@dimen/dp_10"
            android:visibility="invisible"
            app:shape="oval"
            app:shape_solidColor="@color/black30"
            app:shape_solidPressedColor="@color/black60"
            app:srcCompat="@drawable/video_lock_open_ic"
            tools:visibility="visible" />

        <com.hjq.shape.layout.ShapeLinearLayout
            android:id="@+id/ll_player_view_bottom"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom"
            android:gravity="center_vertical"
            android:orientation="horizontal"
            android:paddingHorizontal="@dimen/dp_15"
            android:visibility="invisible"
            app:shape="rectangle"
            app:shape_angle="90"
            app:shape_centerColor="@color/black20"
            app:shape_endColor="@color/transparent"
            app:shape_startColor="#AA000000"
            tools:visibility="visible">

            <androidx.appcompat.widget.AppCompatTextView
                android:id="@+id/tv_player_view_play_time"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="@color/white"
                android:textSize="@dimen/sp_14"
                tools:text="00:00" />

            <androidx.appcompat.widget.AppCompatSeekBar
                android:id="@+id/sb_player_view_progress"
                android:layout_width="0px"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:foreground="@null"
                android:maxHeight="@dimen/dp_2"
                android:paddingVertical="@dimen/dp_10"
                android:progressDrawable="@drawable/video_progress_bg"
                android:thumb="@drawable/video_progress_ball_bg"
                tools:max="100"
                tools:progress="50"
                tools:secondaryProgress="80"
                tools:targetApi="m" />

            <androidx.appcompat.widget.AppCompatTextView
                android:id="@+id/tv_player_view_total_time"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="@color/white"
                android:textSize="@dimen/sp_14"
                tools:text="10:00" />

        </com.hjq.shape.layout.ShapeLinearLayout>

    </FrameLayout>

    <androidx.cardview.widget.CardView
        android:id="@+id/cv_player_view_message"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:gravity="center"
        android:orientation="vertical"
        android:visibility="gone"
        app:cardBackgroundColor="@color/black85"
        app:cardCornerRadius="@dimen/dp_15"
        app:cardElevation="0px"
        tools:visibility="visible">

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:minWidth="@dimen/dp_110"
            android:minHeight="@dimen/dp_110"
            android:orientation="vertical"
            android:padding="@dimen/dp_10">

            <com.airbnb.lottie.LottieAnimationView
                android:id="@+id/lav_player_view_lottie"
                android:layout_width="@dimen/dp_70"
                android:layout_height="@dimen/dp_70"
                app:lottie_autoPlay="false"
                app:lottie_loop="true"
                app:lottie_rawRes="@raw/progress" />

            <com.hjq.widget.view.SmartTextView
                android:id="@+id/tv_player_view_message"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginHorizontal="@dimen/dp_15"
                android:layout_marginTop="@dimen/dp_5"
                android:maxLines="3"
                android:textColor="@color/white"
                android:textSize="@dimen/sp_14"
                tools:text="@string/common_loading" />
        </LinearLayout>

    </androidx.cardview.widget.CardView>

</FrameLayout>


网站公告

今日签到

点亮在社区的每一天
去签到