kotllin自定义view_kotlin自定义view

本文通过创建animator_View类展示了如何在Kotlin中自定义View并利用ValueAnimator实现动画效果。详细介绍了从继承View、设置属性、测量尺寸到在onDraw方法中绘制各个元素的过程,以及如何通过start()和stop()函数控制动画的开始和结束。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

思路:

自定义的view类继承于view类,在xml中赋予它布局属性,在MainActivity中调用xml定义的自己写的view;使用ValueAnimator改变onDraw中绘画的控件的属性,当属性的值改变时,会触发invalidate()函数,系统自己去调用onDraw方法,就形成了动画。

代码:

自定义view的类:

class animator_View : View {

constructor(context: Context,attributeSet: AttributeSet): super(context,attributeSet)

// 高阶函数

var callBack:((Int) -> Boolean)? = null

var pregress = 0

set(value){

field = value

Log.v("yk","我是set + $field")

}

private val mPaint1 by lazy {

Paint().also {

it.color = Color.GRAY

it.style = Paint.Style.FILL

}

}

private val mPaint2 by lazy {

Paint().also {

it.color = Color.BLUE

it.style = Paint.Style.FILL

}

}

private val mPaint3 by lazy {

Paint().also {

it.color = Color.BLUE

it.style = Paint.Style.FILL

}

}

// 画√

private val mPaint4 by lazy {

Paint().also {

it.color = Color.WHITE

it.style = Paint.Style.STROKE

it.strokeWidth = 5f

it.strokeCap = Paint.Cap.ROUND;

}

}

// 线

private var line1X:Float = 0f

private var line1Y:Float = 0f

private var line2X:Float = 0f

private var line2Y:Float = 0f

// 保存图片的宽高

private var ykWidth:Float = 0f

private var ykHeight:Float = 0f

// 第一次图层的y坐标

private var firstX:Float = 0f

// 第二次图片的x 坐标

private var seondX:Float = 0f

private var seconY:Float = 0f

// 第二个图层两端缩进

private var secondStartX:Float = 0f

private var secondEndX:Float = 0f

// 保存图集

private var animatorSet = AnimatorSet()

// 圆角矩形的rect

private var oval3 = RectF(0f,0f,0f,0f)

// 圆角矩形的圆角

private var round:Float = 0f

// 圆形的半径

private var circleRadious:Float = 0f

// 测量控件本身的尺寸

override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {

super.onSizeChanged(w, h, oldw, oldh)

ykWidth = width.toFloat()

ykHeight = height.toFloat()

firstX = height.toFloat()

oval3 = RectF(0f, 0f, ykWidth, ykHeight) // 设置个新的长方形

seconY = height.toFloat()

// 线

line1X = ykWidth/2 - 60f

line1Y = ykHeight/2 - 30f

line2X = ykWidth/2 - 20f

line2Y = ykHeight/2 + 30f

}

@RequiresApi(Build.VERSION_CODES.LOLLIPOP)

override fun onDraw(canvas: Canvas?) {

super.onDraw(canvas)

canvas?.drawRect(0f,0f,ykWidth,firstX,mPaint1)

canvas?.drawRoundRect(secondStartX,0f,secondEndX,seconY,round,round,mPaint2)

// 栏条消失,画一个蓝色圆

canvas?.drawCircle(ykWidth/2.toFloat(),ykHeight/2,circleRadious,mPaint3)

// 画√

// canvas?.drawPath(mPath4,mPaint4)

canvas?.drawLine(ykWidth/2 - 60f,ykHeight/2 - 30f,line1X,line1Y,mPaint4)

canvas?.drawLine(ykWidth/2 - 20f,ykHeight/2 + 30f,line2X,line2Y,mPaint4)

}

// Start启动动画的函数,在主函数中调用(

@RequiresApi(Build.VERSION_CODES.KITKAT)

fun start(){

// 填充蓝条

val animator1 = ValueAnimator.ofFloat(0f,ykWidth).also {

it.duration = 700

it.repeatCount = 0

it.addUpdateListener {yk ->

secondEndX = yk.animatedValue as Float

invalidate()

}

}

// 改变灰色图层的y坐标(让其消失)

val animator2 = ValueAnimator.ofFloat(ykHeight,0f).also {

it.duration = 0

it.repeatCount = 0

it.addUpdateListener {yk ->

firstX = yk.animatedValue as Float

invalidate()

}

}

// 蓝条两边缩进

val animator4 = ValueAnimator.ofFloat(0f,170f).also {

it.duration = 500

it.repeatCount = 0

it.addUpdateListener { yk ->

round = yk.animatedValue as Float

invalidate()

}

}

val animator5 = ValueAnimator.ofFloat(0f,ykWidth/2).also {

it.duration = 500

it.repeatCount = 0

it.addUpdateListener {yk ->

secondStartX = yk.animatedValue as Float

invalidate()

}

}

val animator6 = ValueAnimator.ofFloat(ykWidth,ykWidth/2).also {

it.duration = 500

it.repeatCount = 0

it.addUpdateListener {yk ->

secondEndX = yk.animatedValue as Float

invalidate()

}

}

// 画圆

val animator7 = ValueAnimator.ofFloat(0f,ykHeight/2).also {

it.duration = 100

it.repeatCount = 0

it.addUpdateListener {yk ->

circleRadious = yk.animatedValue as Float

invalidate()

}

}

// 画√(线1)

val animator8 = ValueAnimator.ofFloat(ykWidth/2 - 60f,ykWidth/2 - 20f).also {

it.duration = 500

it.repeatCount = 0

it.startDelay = 500

it.addUpdateListener {yk ->

line1X = yk.animatedValue as Float

invalidate()

}

}

val animator9 = ValueAnimator.ofFloat(ykHeight/2 - 30f,ykHeight/2 + 30f).also {

it.duration = 500

it.repeatCount = 0

it.startDelay = 500

it.addUpdateListener {yk ->

line1Y = yk.animatedValue as Float

invalidate()

}

}

// 线2

val animator10 = ValueAnimator.ofFloat(ykWidth/2 - 20f,ykWidth/2 + 80f).also {

it.duration = 500

it.repeatCount = 0

it.addUpdateListener {yk ->

line2X = yk.animatedValue as Float

invalidate()

}

}

val animator11 = ValueAnimator.ofFloat(ykHeight/2 + 30f,ykHeight/2 - 50f).also {

it.duration = 500

it.repeatCount = 0

it.addUpdateListener {yk ->

line2Y = yk.animatedValue as Float

invalidate()

}

}

animatorSet.playSequentially(animator1,animator2,animator4,animator5)

animatorSet.playTogether(animator5,animator6,animator7)

animatorSet.playSequentially(animator7,animator8)

animatorSet.playTogether(animator8,animator9)

animatorSet.playSequentially(animator9,animator10)

animatorSet.playTogether(animator10,animator11)

if (animatorSet.isPaused){

animatorSet.resume()

}else{

animatorSet.start()

}

}

@RequiresApi(Build.VERSION_CODES.KITKAT)

fun stop(){

animatorSet.end()

}

}

xml布局:

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"

tools:context=".MainActivity">

android:id="@+id/animator_View"

android:layout_width="300dp"

android:layout_height="100dp"

app:layout_constraintBottom_toBottomOf="parent"

app:layout_constraintEnd_toEndOf="parent"

app:layout_constraintHorizontal_bias="0.495"

app:layout_constraintStart_toStartOf="parent"

app:layout_constraintTop_toTopOf="parent"

app:layout_constraintVertical_bias="0.278" />

android:id="@+id/start"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginTop="108dp"

android:text="start"

app:layout_constraintEnd_toEndOf="parent"

app:layout_constraintHorizontal_bias="0.498"

app:layout_constraintStart_toStartOf="parent"

app:layout_constraintTop_toBottomOf="@+id/animator_View" />

MainActivity:

class MainActivity : AppCompatActivity() {

@RequiresApi(Build.VERSION_CODES.KITKAT)

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

setContentView(R.layout.activity_main)

var isStart = true

start.setOnClickListener(){

if (isStart){

animator_View.start()

}else{

animator_View.stop()

}

}

var a = 20

animator_View.callBack = {

Log.v("yk","我被点击了 + $it")

a += 1

animator_View.pregress = a

true

}

}

}

效果:

85de2056dead

QQ视频20201004205628 00_00_00-00_00_30.gif

[可以到github下载(https://github.com/TomFamily/custom_animation_2)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值