Kotlin

kotlin自定义view

2020-10-04  本文已影响0人  书虫大王X
思路:

自定义的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布局:

<androidx.constraintlayout.widget.ConstraintLayout 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"
    tools:context=".MainActivity">

    <com.example.zdy_animation_2.animator_View
        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" />

    <Button
        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" />

</androidx.constraintlayout.widget.ConstraintLayout>

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
        }
    }
}
效果:
QQ视频20201004205628 00_00_00-00_00_30.gif
[可以到github下载(https://github.com/TomFamily/custom_animation_2)
上一篇下一篇

猜你喜欢

热点阅读