查看: 769|回复: 0

[手机开发] Android自定义加载圈动画效果

发表于 2017-12-25 08:00:00

本文实例为大家分享了Android自定义加载圈动画展示的具体代码,供大家参考,具体内容如下

实现如下效果:

该效果图主要有3个动画:
1.旋转动画
2.聚合动画
3.扩散动画

以上3个动画都是通过ValueAnimator来实现,配合自定义View的onDraw()方法实现不断的刷新和绘制界面.

具体代码如下:

  1. package blog.csdn.net.mchenys.myanimationloading;
  2. import android.animation.Animator;
  3. import android.animation.AnimatorListenerAdapter;
  4. import android.animation.ValueAnimator;
  5. import android.content.Context;
  6. import android.graphics.Canvas;
  7. import android.graphics.Color;
  8. import android.graphics.Paint;
  9. import android.graphics.PointF;
  10. import android.util.AttributeSet;
  11. import android.view.View;
  12. import android.view.animation.LinearInterpolator;
  13. import android.view.animation.OvershootInterpolator;
  14. /**
  15. * Created by mChenys on 2016/5/21.
  16. */
  17. public class AnimationLoading extends View {
  18. private float mBigCircleRaduis = 90;//大圆的半径
  19. private float mSubCircleRadius = 20;//小圆的半径
  20. private PointF mBigCenterPoint;//大圆的圆心坐标
  21. private Paint mBgPaint;//绘制背景的画笔
  22. private Paint mFgPaint;//绘制前景色的画笔
  23. private AnimatorTemplet mTemplet;//动画模板
  24. float mBigCircleRotateAngle;//大圆旋转的角度
  25. float mDiagonalDist;//屏幕对角线一半的距离
  26. float mBgStrokeCircleRadius;//用于作为绘制背景空心圆的半径
  27. //6个小圆的颜色
  28. private int[] colors = new int[]{Color.RED, Color.DKGRAY, Color.YELLOW, Color.BLUE, Color.LTGRAY, Color.GREEN};
  29. public AnimationLoading(Context context) {
  30. this(context, null);
  31. }
  32. public AnimationLoading(Context context, AttributeSet attrs) {
  33. super(context, attrs);
  34. init();
  35. }
  36. @Override
  37. protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  38. super.onSizeChanged(w, h, oldw, oldh);
  39. //确定大圆的圆心坐标
  40. mBigCenterPoint.x = w / 2f;
  41. mBigCenterPoint.y = h / 2f;
  42. //屏幕对角线的一半
  43. mDiagonalDist = (float) (Math.sqrt(w * w + h * h) / 2);
  44. }
  45. private void init() {
  46. mBigCenterPoint = new PointF();
  47. mFgPaint = new Paint();
  48. mFgPaint.setAntiAlias(true);
  49. mBgPaint = new Paint(mFgPaint);
  50. mBgPaint.setColor(Color.WHITE);
  51. mBgPaint.setStyle(Paint.Style.STROKE);
  52. }
  53. @Override
  54. protected void onDraw(Canvas canvas) {
  55. if (null == mTemplet) {
  56. //开启旋转动画
  57. mTemplet = new RotateState();
  58. }
  59. //传递Canvas对象
  60. mTemplet.drawState(canvas);
  61. }
  62. /**
  63. * 绘制圆
  64. *
  65. * @param canvas
  66. */
  67. private void drawCircle(Canvas canvas) {
  68. //获取每个小圆间隔的角度
  69. float rotateAngle = (float) (2 * Math.PI / colors.length);
  70. for (int i = 0; i < colors.length; i++) {
  71. //每个小圆的实际角度
  72. double angle = rotateAngle * i + mBigCircleRotateAngle; //这里加上大圆旋转的角度是为了带动小圆一起旋转
  73. //计算每个小圆的圆心坐标
  74. float cx = (float) (mBigCircleRaduis * Math.cos(angle)) + mBigCenterPoint.x;
  75. float cy = (float) (mBigCircleRaduis * Math.sin(angle)) + mBigCenterPoint.y;
  76. //绘制6个小圆
  77. mFgPaint.setColor(colors[i]);
  78. canvas.drawCircle(cx, cy, mSubCircleRadius, mFgPaint);
  79. }
  80. }
  81. /**
  82. * 绘制背景
  83. *
  84. * @param canvas
  85. */
  86. private void drawBackground(Canvas canvas) {
  87. if (mBgStrokeCircleRadius > 0f) {
  88. //不断扩散的空心圆,空心圆的半径为屏幕对角线的一半,空心圆的线宽则从线宽一半到0
  89. float strokeWidth = mDiagonalDist - mBgStrokeCircleRadius;//线宽从对角线的1/2 ~ 0
  90. mBgPaint.setStrokeWidth(strokeWidth);
  91. float radius = mBgStrokeCircleRadius + strokeWidth / 2;//半径从对角线的1/4 ~ 1/2
  92. canvas.drawCircle(mBigCenterPoint.x, mBigCenterPoint.y,radius , mBgPaint);
  93. } else {
  94. //绘制白色背景
  95. canvas.drawColor(Color.WHITE);
  96. }
  97. }
  98. private abstract class AnimatorTemplet {
  99. abstract void drawState(Canvas canvas);
  100. }
  101. /**
  102. * 绘制旋转动画
  103. */
  104. private class RotateState extends AnimatorTemplet {
  105. ValueAnimator mValueAnimator;
  106. public RotateState() {
  107. //旋转的过程,就是不断的获取大圆的角度,从0-2π
  108. mValueAnimator = ValueAnimator.ofFloat(0, (float) Math.PI * 2);
  109. mValueAnimator.setInterpolator(new LinearInterpolator());//匀速插值器
  110. mValueAnimator.setDuration(1200);
  111. mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
  112. @Override
  113. public void onAnimationUpdate(ValueAnimator animation) {
  114. //获取大圆旋转的角度
  115. mBigCircleRotateAngle = (float) animation.getAnimatedValue();
  116. //重绘
  117. invalidate();
  118. }
  119. });
  120. mValueAnimator.setRepeatCount(ValueAnimator.INFINITE);//无限循环
  121. mValueAnimator.start();
  122. }
  123. /**
  124. * 停止旋转动画,在数据加载完毕后供外部调用
  125. */
  126. public void stopRotate() {
  127. mValueAnimator.cancel();
  128. }
  129. @Override
  130. void drawState(Canvas canvas) {
  131. drawBackground(canvas);
  132. drawCircle(canvas);
  133. }
  134. }
  135. /**
  136. * 绘制聚合动画
  137. */
  138. private class MergingState extends AnimatorTemplet {
  139. public MergingState() {
  140. //聚合的过程,就是不断的改变大圆的半径,从mBigCircleRaduis~0
  141. ValueAnimator valueAnimator = ValueAnimator.ofFloat(mBigCircleRaduis, 0);
  142. valueAnimator.setInterpolator(new OvershootInterpolator(10f));//弹性插值器
  143. valueAnimator.setDuration(600);
  144. valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
  145. @Override
  146. public void onAnimationUpdate(ValueAnimator animation) {
  147. //获取大圆变化的半径
  148. mBigCircleRaduis = (float) animation.getAnimatedValue();
  149. //重绘
  150. invalidate();
  151. }
  152. });
  153. valueAnimator.addListener(new AnimatorListenerAdapter() {
  154. @Override
  155. public void onAnimationEnd(Animator animation) {
  156. //聚合执行完后进入下一个扩散动画
  157. mTemplet = new SpreadState();
  158. }
  159. });
  160. valueAnimator.start();
  161. }
  162. @Override
  163. void drawState(Canvas canvas) {
  164. drawBackground(canvas);
  165. drawCircle(canvas);
  166. }
  167. }
  168. /**
  169. * 绘制扩散动画
  170. */
  171. private class SpreadState extends AnimatorTemplet {
  172. public SpreadState() {
  173. //扩散的过程,就是不断的改变背景画绘制空心圆的半径,从0~mDiagonalDist
  174. ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, mDiagonalDist);
  175. valueAnimator.setDuration(600);
  176. valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
  177. @Override
  178. public void onAnimationUpdate(ValueAnimator animation) {
  179. //获取大圆变化的半径
  180. mBgStrokeCircleRadius = (float) animation.getAnimatedValue();
  181. //重绘
  182. invalidate();
  183. }
  184. });
  185. valueAnimator.start();
  186. }
  187. @Override
  188. void drawState(Canvas canvas) {
  189. drawBackground(canvas);
  190. }
  191. }
  192. /**
  193. * 停止加载动画
  194. */
  195. public void stopLoading() {
  196. if (null != mTemplet && mTemplet instanceof RotateState) {
  197. ((RotateState) mTemplet).stopRotate();
  198. //开启下一个聚合动画
  199. post(new Runnable() {
  200. @Override
  201. public void run() {
  202. mTemplet = new MergingState();
  203. }
  204. });
  205. }
  206. }
  207. }
复制代码

测试的Activity

  1. package blog.csdn.net.mchenys.myanimationloading;
  2. import android.os.Bundle;
  3. import android.os.Handler;
  4. import android.support.v7.app.AppCompatActivity;
  5. import android.widget.FrameLayout;
  6. import android.widget.ImageView;
  7. public class MainActivity extends AppCompatActivity {
  8. @Override
  9. protected void onCreate(Bundle savedInstanceState) {
  10. super.onCreate(savedInstanceState);
  11. FrameLayout content = new FrameLayout(this);
  12. content.setOnClickListener(null);
  13. ImageView bg = new ImageView(this);
  14. bg.setImageResource(R.drawable.fg);
  15. bg.setScaleType(ImageView.ScaleType.FIT_XY);
  16. content.addView(bg);
  17. final AnimationLoading loading = new AnimationLoading(this);
  18. content.addView(loading);
  19. setContentView(content);
  20. new Handler().postDelayed(new Runnable() {
  21. @Override
  22. public void run() {
  23. //3s后停止加载动画
  24. loading.stopLoading();
  25. }
  26. },3000);
  27. }
  28. }
复制代码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持程序员之家。



回复

使用道具 举报