自定义view之视频播放状态标识
kotlin学习
今天写的东西比较简单,一个自定义view,主要是为了捡捡kotlin语法。废话不多说,先上效果
文章图片
【自定义view之视频播放状态标识】这个效果通常在一些播放器上遇到,用来标识视频正在播放中。
根据这个效果我们先明确一下我们需要做的:
1.绘制三条竖线
2.开启动画让它动起来
3.自定义一些属性方便使用和扩展
下面我会直接贴一下代码,代码并不复杂,但是我希望大家带着一些问题去看,比如
为什么这里需要重写onMeasure方法?
canvas在drawLine的时候需要考虑线的宽度吗?
什么时候应该停止动画?
kotlin中init代码块和构造函数中代码的哪个先执行?
自定义view代码:
package com.example.viewimport 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.Rclass 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自带的格式化真的能逼疯我这强迫症~~
推荐阅读
- PMSJ寻平面设计师之现代(Hyundai)
- 太平之莲
- 闲杂“细雨”
- 七年之痒之后
- 深入理解Go之generate
- 由浅入深理解AOP
- 期刊|期刊 | 国内核心期刊之(北大核心)
- 生活随笔|好天气下的意外之喜
- 感恩之旅第75天
- python学习之|python学习之 实现QQ自动发送消息