这篇文章主要介绍了Android开发的自定义加载动画,效果为一个连续的动画,就是这个大圆不停地吞下小圆,文中示例代码讲解详细,感兴趣的可以了解一下
一、demo简介
1.效果如下图所示。我切了三个瞬间,但其实这是一个连续的动画,就是这个大圈不停的吞小。
2.这个动画可以分为两部分。第一,大圆张开嘴闭上嘴的动画相当于画了一个圆弧,指定它的角度就好了。圆圈是从右向左移动的动画。然后不断刷新界面,让动画的持续时间是永恒的,这样才会有持续的动态效果。
二、分析贪吃动画的尺寸比例
1.在制作动画之前,我们要建立一个模型,确定大圆和小圆的比例。这个比例是自己设定的,可以自己修改。下图是画布宽度大于高度的情况。
R =最小高度/6
Cx =(宽度-最小宽度)/2 + 3R
Cy =高度/2
还有画布宽度小于高度的情况,如下图所示:此时
6R+0.5R+2R =最小宽度.R =最小宽度/8.5
Cx = 3R
Cy =高度/2
2.确定了大圆的圆心坐标后,也可以知道小圆的圆心坐标。
三、画圆
1.首先创建一个从view继承的类,并实现其对应的构造方法。
class MouseLoadingView : 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){}}
2.定义大圆(嘴)的半径(3R),小圆的半径(r)和两个圆之间的距离(0.5R),嘴的圆心坐标。
//嘴的半径 private var mouseRadius = 0f //小圆的半径 private var ballRadius = 0f //嘴和小球的间距 private var space = 0f //嘴的圆心 private var cx = 0f private var cy = 0f
3.在onSizeChanged方法中计算大小。
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { if(measuredWidthgt;=measuredHeight){ ballRadius= measuredHeight/6f cx = (measuredWidth-8.5f*ballRadius)/2 + 3*ballRadius }else{ ballRadius= measuredWidth/8.5f cx = 3*ballRadius.toFloat() } mouseRadius = 3*ballRadius space = ballRadius/2f cy = measuredHeight/2f }
4.提供画笔
//画笔 private val mPaint = Paint().apply { style = Paint.Style.FILL color = context.resources.getColor(R.color.colorAccent,null) }
5.用onDraw方法画一个圆
override fun onDraw(canvas: Canvas) { canvas.drawCircle(cx,cy,mouseRadius,mPaint)}
6.在xml文件中添加这个自定义类
lt;com.example.loadinganim.MouseLoadingView android:id="@+id/loadingView" android:layout_width="100dp" android:layout_height="100dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.498" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.11" /gt;
7.如果用上面的方法画圆,会出现一些bug,如下图。
这是因为,当宽度大于高度时,R=高度/6。如果r太小,那么圆心的坐标就剩了,然后有些圆就出界了。为了避免这种情况,在任何情况下都要将R设为最小的/8.5。
8.重新计算半径
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { super.onSizeChanged(w, h, oldw, oldh) //计算尺寸 //小球的半径 ( Math.min(measuredHeight,measuredWidth)/8.5f ).also {r-gt; ballRadius = r //嘴的半径 mouseRadius = 3*r //嘴和小球的间距 space = r/2 //嘴的圆心 cx = ((measuredWidth- 8.5*r)/2 + 3*r).toFloat() cy = measuredHeight/2f } }
四、实现张嘴闭嘴动画
1.张嘴就相当于画了一个弧线。画圆弧需要确定一个矩形区域;;也就是大圆所在的矩形。你还需要设置一个角度,也就是弧度。如下图所示画出来。
override fun onDraw(canvas: Canvas) { canvas.drawArc( cx-mouseRadius, cy-mouseRadius, cx+mouseRadius, cy+mouseRadius, 45f,270f,true,mPaint )}
image.png
2.这是一个静态过程。如果想让它有动感,只需要不断修改张嘴的角度就可以了。所以我们定义一个动画因子为弧度。
//嘴张开的角度 - gt;张嘴的动画因子 private var mouseAngle = 0f
3.然后在onDraw方法中,将死数据更改为我们的动画因子。
canvas.drawArc( cx-mouseRadius, cy-mouseRadius, cx+mouseRadius, cy+mouseRadius, mouseAngle,360-2*mouseAngle,true,mPaint )
4.添加两个按钮来显示动画和暂停动画。当按钮被点击时,相应的点击事件被实现。
5.所以在MouseLoadingView类中,为外部调用提供了几个方法。
} //提供给外部使用 //显示动画 fun show(){ createAnimator() start() } //隐藏动画 fun hide(){ stop() }
6.createAnimator()是一个创建动画的函数。从0-45-0是动画因子的变化。听动画执行的过程,不断刷新动画因子的值,然后刷新界面。
private fun createAnimator() { ValueAnimator.ofFloat(0f, 45f, 0f).apply { duration = 650 repeatCount = ValueAnimator.INFINITE addUpdateListener { mouseAngle = it.animatedValue as Float //刷新界面 invalidate() } animators.add(this) }}
7.因为有很多动画效果,所以我们要用一个数组来保存所有的动画。
//保存所有的动画对象 private var animators = mutableListOflt;ValueAnimatorgt;()
8.添加几种开始和结束动画的方法
//启动动画 private fun start(){ for(anim in animators){ anim.start() } }//暂停动画 private fun stop(){ for(anim in animators){ anim.end() }
五、小球移动动画
1.创建一个小球,然后让它从右边移动到左边。小球圆心的x坐标是不断变化的,y坐标和大圆是一样的。所以我们要为球设置一个移动的动画因子。
//小球移动的动画因子 private var ballTranslateX = 0f
2.然后在onDraw()方法中画球。
//绘制小球canvas.drawCircle(cx+ballTranslateX,cy,ballRadius,mPaint)
3.之后,在createAnimator()方法中添加球的动画。让球从4.5R移动到0,也就是直到小圆和大圆重合。
ValueAnimator.ofFloat(4.5f*ballRadius, 0f).apply { duration = 650 repeatCount = ValueAnimator.INFINITE addUpdateListener { ballTranslateX = it.animatedValue as Float //刷新界面 invalidate() } animators.add(this) }
4.在MainActivity中添加按钮click事件。
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) startBtn.setOnClickListener{ loadingView.show() pauseView.show() } stopBtn.setOnClickListener { loadingView.hide() pauseView.hide() } }}
大概就是这样。自定义动画加载的难点在于寻找动画因子。
以上是Android开发的定制加载动画的详细内容。更多安卓加载动画信息
精彩评论