Android 自定义数据加载动画

最终效果

自定义数据加载动画

实现思路

View绘制
整体是一个组合View,我们可以通过继承RelativeLayout(因为中间圆点需要居中),往里面添加三个圆点来实现;

动画效果
一开始三个圆点均处于RelativeLayout中间,左右两个圆点需要平移到两侧,平移结束后再平移到中间位置,此时需要改变圆点颜色,中间平移结束后再次左右平移,如此反复,即可实现最终效果。

相关源码

  • 首先,自定义一个CircleView,用于表示每个圆点
package com.crystal.view.animation

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

/**
* 圆点
* on 2022/11/9
*/
class CircleView : View {
   /**
    * 画笔工具
    */
   private var paint: Paint = Paint()

   constructor(context: Context) : this(context, null)
   constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
   constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
       context,
       attrs,
       defStyleAttr
   ) {
       paint.isAntiAlias = true
       paint.isDither = true
   }


   override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
       super.onMeasure(widthMeasureSpec, heightMeasureSpec)
       //设置宽高相等
       var widthSize = MeasureSpec.getSize(widthMeasureSpec)
       var heightSize = MeasureSpec.getSize(heightMeasureSpec)
       if (widthSize > heightSize) {
           widthSize = heightSize
       } else {
           heightSize = widthSize
       }
       setMeasuredDimension(widthSize, heightSize)
   }

   override fun onDraw(canvas: Canvas) {
       //绘制圆
       canvas.drawCircle(width / 2f, width / 2f, width / 2f, paint)
   }


   /**
    * 为圆形渲染上颜色
    */
   fun renderCircleColor(color: Int) {
       paint.color = color
       invalidate()
   }

   /**
    * 获取渲染颜色
    */
   fun getRenderColor(): Int {
       return paint.color
   }

}
  • 自定义数据加载动画ExChangeLoadingView
package com.crystal.view.animation

import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.content.Context
import android.graphics.Color
import android.util.AttributeSet
import android.util.TypedValue
import android.view.animation.AccelerateInterpolator
import android.view.animation.DecelerateInterpolator
import android.widget.RelativeLayout

/**
* 圆点加载动画
* on 2022/11/9
*/
class ExChangeLoadingView : RelativeLayout {

   /**
    * 左侧圆点
    */
   private lateinit var leftCircleView: CircleView

   /**
    * 中间圆点
    */
   private lateinit var middleCircleView: CircleView

   /**
    * 右侧圆点
    */
   private lateinit var rightCircleView: CircleView

   /**
    * 左右运动的距离
    */
   private var distanceX = dp2px(40).toFloat()


   constructor(context: Context) : this(context, null)
   constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
   constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
       context, attrs, defStyleAttr
   ) {
       //在view测量之后进行绘制
       post {
           initViews()
           //左侧和右侧圆点分别向两侧运动
           outerAnimation()
       }
   }

   /**
    * 左右圆点向两侧运动
    */
   private fun outerAnimation() {
       val leftAnimator = ObjectAnimator.ofFloat(leftCircleView, "translationX", 0f, -distanceX)
       val rightAnimator = ObjectAnimator.ofFloat(rightCircleView, "translationX", 0f, distanceX)
       val animatorSet = AnimatorSet()
       //设置加速差值器
       animatorSet.interpolator = AccelerateInterpolator()
       animatorSet.duration = 500L
       animatorSet.playTogether(leftAnimator, rightAnimator)
       animatorSet.addListener(object : AnimatorListenerAdapter() {
           override fun onAnimationEnd(animation: Animator) {
               //动画结束后,左右圆点向中间运动
               innerAnimation()
           }
       })
       animatorSet.start()
   }

   /**
    * 左右圆点向中心运动
    */
   private fun innerAnimation() {
       val leftAnimator = ObjectAnimator.ofFloat(leftCircleView, "translationX", -distanceX, 0f)
       val rightAnimator = ObjectAnimator.ofFloat(rightCircleView, "translationX", distanceX, 0f)
       val animatorSet = AnimatorSet()
       //设置减速差值器
       animatorSet.interpolator = DecelerateInterpolator()
       animatorSet.duration = 500L
       animatorSet.playTogether(leftAnimator, rightAnimator)
       animatorSet.addListener(object : AnimatorListenerAdapter() {
           override fun onAnimationEnd(animation: Animator) {
               //动画结束后,左右圆点向中间运动
               outerAnimation()
               exChangeCircleColor()
           }
       })
       animatorSet.start()
   }


   private fun initViews() {
       //添加三个View
       val layoutParams = LayoutParams(dp2px(10), dp2px(10))
       layoutParams.addRule(CENTER_IN_PARENT)

       leftCircleView = CircleView(context)
       leftCircleView.renderCircleColor(Color.BLUE)
       leftCircleView.layoutParams = layoutParams
       addView(leftCircleView)

       rightCircleView = CircleView(context)
       rightCircleView.renderCircleColor(Color.RED)
       rightCircleView.layoutParams = layoutParams
       addView(rightCircleView)

       middleCircleView = CircleView(context)
       middleCircleView.renderCircleColor(Color.GREEN)
       middleCircleView.layoutParams = layoutParams
       //中间圆形最后添加覆盖在另两个之上
       addView(middleCircleView)
   }

   private fun dp2px(dp: Int): Int {
       return TypedValue.applyDimension(
           TypedValue.COMPLEX_UNIT_DIP,
           dp.toFloat(),
           resources.displayMetrics
       ).toInt()
   }

   /**
    * 进行三个圆形颜色变化 左边的颜色给中间  中间的给右边  右边的颜色给左边
    */
   private fun exChangeCircleColor() {
       val leftColor = leftCircleView.getRenderColor()
       val middleColor = middleCircleView.getRenderColor()
       val rightColor = rightCircleView.getRenderColor()
       middleCircleView.renderCircleColor(leftColor)
       rightCircleView.renderCircleColor(middleColor)
       leftCircleView.renderCircleColor(rightColor)
   }
}

总结

看似复杂的效果,其实将效果一步步进行拆分后,实际实现的代码竟如此简单。

结语

如果以上文章对您有一点点帮助,希望您不要吝啬的点个赞加个关注,您每一次小小的举动都是我坚持写作的不懈动力!ღ( ´・ᴗ・` )

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值