无名之辈的Android之路

自定义View的使用:数据加载进度动画

2021-08-24  本文已影响0人  搬码人

引入

在申请网络数据的过程中,需要界面展示正在获取数据的状态。比如在腾讯视频获取数据未完成时,屏幕中央会有三个模型缩放的动画。要实现这样的动画效果,就需要利用自定义View来实现


绘制草图

自定义View的创建步骤

 constructor(context: Context):super(context){}
    constructor(context: Context,attrs:AttributeSet?):super(context,attrs){}
    constructor(context: Context,attrs: AttributeSet?,style:Int):super(context,attrs,style){}
 override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        //两种情况设置圆的半径
        radius = if ((measuredHeight/2)*7 <= measuredWidth){
            measuredHeight/2f
        }else{
            measuredWidth/7f

        }
        cy = measuredHeight/2f
        cx = measuredWidth/2f -2.5f*radius
    }

两种画多个圆的方式

-1 普通的画圆方式
直接多次调用canvas?.drawCircle

        canvas?.drawCircle(cx,cy,radius,mPaint)
        canvas?.drawCircle(cx+2.5f*radius,cy,radius,mPaint)
        canvas?.drawCircle(cx+5f*radius,cy,radius,mPaint)

-2 通过移动画布的方式
canvas?.save():保存当前的状态
canvas?.translate:移动画布
canvas?.restore:画布恢复到初始状态,比如位置返回至初始的位置。

 override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        canvas?.save()
        //将画布移动到cx cy的位置
        //cx 和 cy表示移动的距离
        canvas?.translate(cx,cy)
        //绘制一个圆
        canvas?.drawCircle(0f,0f,radius,mPaint)
        //移动画布至第二个圆的圆心
        canvas?.translate(2.5f*radius,0f)
        //绘制第二个圆
        canvas?.drawCircle(cx,cy,radius,mPaint)
        
        //绘制第三个圆
        canvas?.translate(2.5f*radius,0f)
        canvas?.drawCircle(0f,0f,radius,mPaint)
        canvas?.restore()
        
    }

自定义进度代码

创建createAnimator()方法实现缩放动画。
为使三个圆有一次缩放的效果,使用数组的方式将动画的延迟时间和初始比例都放进数组中,当然动画对象也需要放入数组中,在createAnimator方法中利用for()依次对动画对象mAnimators进行配置。
ValueAnimator属性动画
invalidate触发绘制(刷新)

package com.example.falltype

import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.util.AttributeSet
import android.view.View

/**
 *@Description
 *@Author PC
 *@QQ 1578684787
 */
class PulseLoadingView:View {
    //圆的半径
    private var radius = 0f
    //第一个圆的坐标
    private var cx = 0f
    private var cy = 0f
    //画笔
    private val mPaint = Paint().apply {
        color = context.resources.getColor(R.color.main_purple)
        style = Paint.Style.FILL
    }
    //动画对象
    private  var mAnimators = mutableListOf<ValueAnimator>()
    //保存延时的时间
    private var delays = arrayOf(100L,200L,300L)
    //保存每个圆缩放的比例
    private val scales = arrayOf(0.2f,0.2f,0.2f)
    constructor(context: Context):super(context){}
    constructor(context: Context,attrs:AttributeSet?):super(context,attrs){}
    constructor(context: Context,attrs: AttributeSet?,style:Int):super(context,attrs,style){}

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        //两种情况设置圆的半径
        radius = if ((measuredHeight/2)*7 <= measuredWidth){
            measuredHeight/2f
        }else{
            measuredWidth/7f

        }
        cy = measuredHeight/2f
        cx = measuredWidth/2f -2.5f*radius
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        for (i in 0..2){
            canvas?.save()
            canvas?.translate(cx+i*2.5f*radius,cy)
            canvas?.scale(scales[i],scales[i])
            canvas?.drawCircle(0f,0f,radius,mPaint)
            canvas?.restore()
        }

//一般的画圆方式
//        canvas?.drawCircle(cx,cy,radius,mPaint)
//        canvas?.drawCircle(cx+2.5f*radius,cy,radius,mPaint)
//        canvas?.drawCircle(cx+5f*radius,cy,radius,mPaint)

    }
    private fun createAnimator(){
        for (i in 0..2) {
            ValueAnimator.ofFloat(0.2f, 1f).apply {
                duration = 600
                startDelay = delays[i] // 设置每个圆对应的延迟时间
                repeatCount = ValueAnimator.INFINITE
                addUpdateListener {
                    scales[i] = it.animatedValue as Float
                    invalidate()
                }
                mAnimators.add(this)
            }
        }
    }
    private fun start(){
        for (item in mAnimators){
            item.start()
        }
    }
    private fun stop(){
        for (item in mAnimators){
            item.end()
        }
    }
   //启动动画
    fun show(){
        createAnimator()
       start()
    }

    //隐藏动画
    fun hide(){
        stop()
    }

}

在MainActivity设置按钮点击事件,欣赏进度动画的效果

package com.example.falltype

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.falltype.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {
    lateinit var mbinding:ActivityMainBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mbinding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(mbinding.root)

        mbinding.mStart.setOnClickListener {
            mbinding.loadingView.show()
        }
        mbinding.stop.setOnClickListener {
            mbinding.loadingView.hide()
        }
    }
}

运行效果
点击start


数据加载动画效果
上一篇下一篇

猜你喜欢

热点阅读