引入
在申请网络数据的过程中,需要界面展示正在获取数据的状态。比如在腾讯视频获取数据未完成时,屏幕中央会有三个模型缩放的动画。要实现这样的动画效果,就需要利用自定义View来实现
绘制草图
自定义View的创建步骤
- 1 重写构造方法
constructor(context: Context):super(context){}
constructor(context: Context,attrs:AttributeSet?):super(context,attrs){}
constructor(context: Context,attrs: AttributeSet?,style:Int):super(context,attrs,style){}
- 2 继承onSizeChanged方法对view的元素进行设置
如:自定义画圆设置半径与圆心
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
}
- 3 继承onDraw方法进行绘制
画圆的几个重要条件:半径,圆心,画笔Paint()
两种画多个圆的方式
-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
数据加载动画效果
网友评论