自定义view之视频播放状态标识

kotlin学习


今天写的东西比较简单,一个自定义view,主要是为了捡捡kotlin语法。废话不多说,先上效果
自定义view之视频播放状态标识_第1张图片

这个效果通常在一些播放器上遇到,用来标识视频正在播放中。
根据这个效果我们先明确一下我们需要做的:
1.绘制三条竖线
2.开启动画让它动起来
3.自定义一些属性方便使用和扩展
下面我会直接贴一下代码,代码并不复杂,但是我希望大家带着一些问题去看,比如
为什么这里需要重写onMeasure方法?
canvas在drawLine的时候需要考虑线的宽度吗?
什么时候应该停止动画?
kotlin中init代码块和构造函数中代码的哪个先执行?
自定义view代码:

package com.example.view

import android.animation.AnimatorSet
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.util.AttributeSet
import android.view.View
import com.example.kotlinsturdy.R

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

    companion object {
        private const val DEFAULT_WIDTH = 20
        private const val DEFAULT_HEIGHT = 60
        private const val DEFAULT_LINE_WIDTH = 10
        private const val DEFAULT_LINE_HEIGHT = 60
    }

    private val firstLineHeight: Float
    private val secondLineHeight: Float
    private val thirdLineHeight: Float
    private val lineWidth: Float
    private var firstLineCurrentHeight = 0f
    private var secondLineCurrentHeight = 0f
    private var thirdLineCurrentHeight = 0f
    private lateinit var mPaint: Paint
    private val lineColor: Int
    private var animatorSet: AnimatorSet? = null
    private fun initPaint() {
        mPaint = Paint(Paint.ANTI_ALIAS_FLAG)
        mPaint.color = lineColor
        mPaint.strokeWidth = lineWidth
    }

    init {
        val array = context.obtainStyledAttributes(attrs, R.styleable.PlayingView)
        firstLineHeight = array.getDimension(
            R.styleable.PlayingView_firstLineHeight,
            DEFAULT_LINE_HEIGHT.toFloat()
        )
        firstLineCurrentHeight = firstLineHeight.times(0.3f)
        secondLineHeight = array.getDimension(
            R.styleable.PlayingView_secondLineHeight,
            DEFAULT_LINE_HEIGHT.toFloat()
        )
        secondLineCurrentHeight = secondLineHeight
        thirdLineHeight = array.getDimension(
            R.styleable.PlayingView_thirdLineHeight,
            DEFAULT_LINE_HEIGHT.toFloat()
        )
        thirdLineCurrentHeight = thirdLineHeight.times(0.3f)
        lineWidth = array.getDimension(
            R.styleable.PlayingView_lineWidth,
            DEFAULT_LINE_WIDTH.toFloat()
        )
        lineColor =
            array.getColor(R.styleable.PlayingView_lineColor, Color.BLUE)
        array.recycle()
        initPaint()
    }

    fun startPlayingAnimation() {
        if (animatorSet == null) {
            animatorSet = AnimatorSet()
            val animatorFirst = ValueAnimator.ofFloat(0.3f, 1f, 0.3f)
            animatorFirst.duration = 1000
            animatorFirst.repeatCount = ValueAnimator.INFINITE
            animatorFirst.addUpdateListener { animation ->
                firstLineCurrentHeight =
                    (firstLineHeight * animation.animatedValue as Float)
                secondLineCurrentHeight =
                    (secondLineHeight * animation.animatedValue as Float)
                thirdLineCurrentHeight =
                    (thirdLineHeight * animation.animatedValue as Float)
                invalidate()
            }
            val animatorSecond = ValueAnimator.ofFloat(1f, 0.3f, 1f)
            animatorSecond.duration = 1000
            animatorSecond.repeatCount = ValueAnimator.INFINITE
            animatorSecond.addUpdateListener { animation ->
                secondLineCurrentHeight =
                    (secondLineHeight * animation.animatedValue as Float)
            }
            animatorSet!!.playTogether(animatorFirst, animatorSecond)
        }
        if (!animatorSet!!.isRunning) {
            animatorSet!!.start()
        }
    }

    fun setLineColor(color: Int) {
        mPaint.color = color
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        drawFirstLine(canvas)
        drawSecondLine(canvas)
        drawThirdLine(canvas)
    }

    private fun drawFirstLine(canvas: Canvas) {
        canvas.drawLine(
            paddingLeft + lineWidth / 2,
            height - firstLineCurrentHeight,
            paddingLeft + lineWidth / 2,
            height - paddingBottom.toFloat(),
            mPaint
        )
    }

    private fun drawSecondLine(canvas: Canvas) {
        //保证第二个肯定是在中间位置 需要考虑padding
        canvas.drawLine(
            paddingLeft + (width - paddingLeft - paddingRight) / 2.toFloat(),
            height - secondLineCurrentHeight,
            paddingLeft + (width - paddingLeft - paddingRight) / 2.toFloat(),
            height - paddingBottom.toFloat(),
            mPaint
        )
    }

    private fun drawThirdLine(canvas: Canvas) {
        canvas.drawLine(
            width - paddingRight - (lineWidth / 2),
            height - thirdLineCurrentHeight,
            width - paddingRight - (lineWidth / 2),
            height - paddingBottom.toFloat(),
            mPaint
        )
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        releaseAnimation()
    }

    override fun setVisibility(visibility: Int) {
        super.setVisibility(visibility)
        if (visibility == GONE || visibility == INVISIBLE) {
            releaseAnimation()
        }
    }

    private fun releaseAnimation() {
        if (animatorSet != null) {
            animatorSet!!.cancel()
            animatorSet = null
        }
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        val widthSpecMode = MeasureSpec.getMode(widthMeasureSpec)
        val widthSize = MeasureSpec.getSize(widthMeasureSpec)
        val heightSpecMode = MeasureSpec.getMode(widthMeasureSpec)
        val heightSize = MeasureSpec.getSize(widthMeasureSpec)
        if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(
                DEFAULT_WIDTH,
                DEFAULT_HEIGHT
            )
        } else if (widthSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(DEFAULT_WIDTH, heightSize)
        } else if (heightSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(widthSize, DEFAULT_HEIGHT)
        }
    }
}

自定义属性:

 
        
        
        
        
        
    

布局中使用:


吐槽一下:android studio自带的格式化真的能逼疯我这强迫症~~

你可能感兴趣的:(Kotlin)