Material Design 过渡动画

materailDesign过度动画

怎么样,很炫吧

github地址

定义个接口

1
2
3
public interface LoadState {
void drawState(Canvas canvas);
}

自定义view实现加载动画

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
/**
* Created by marc on 2017/6/28.
*/
public class LoadView extends View {
/**
* 大圆的半径(里面含有好多小圆)
*/
private float mRotationRadius = 90;
/**
* 小圆的半径
*/
private float mCircleRadius = 18;
/**
* 小圆的颜色列表
*/
private int[] mCircleColors;
/**
* 小圆旋转一周需要的时间
*/
private long mRotationDuration = 1200;
/**
* 其他动画执行的时间(除了旋转的动画)
*/
private long mSplashDuration = 500;
/**
* view的背景颜色
*/
private int mBgColor = Color.WHITE;
/**
* 当前大圆的半径(动态变化)
*/
private float mCurrentRatationRadios;
/**
* 当前大圆旋转的角度(弧度)
*/
private float mCurrentRotationAngle = 0f;
/**
* 空心圆半径
*/
private float mHoleRadius = 0f;
/**
* 绘制圆的画笔
*/
private Paint mPaint = new Paint();
/**
* 绘制背景的画笔
*/
private Paint mBgPaint = new Paint();
/**
* view中心的坐标
*/
private float mCenterX;
private float mCenterY;
/**
* view对角线的一半
*/
private float mDiagonalDist;
/**
* 保存当前动画状态-->当前在执行那种动画
*/
private LoadState mState = null;
/**
* 小圆之间的间隔角度
*/
private float mRotationAngle = 0f;
/**
* 聚合后缩放圆的半径
*/
private float mScaleCircle;
public LoadView(Context context) {
this(context, null);
}
public LoadView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public LoadView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
/**
* 初始化
*/
private void init(Context context) {
//抗锯齿
mPaint.setAntiAlias(true);
mBgPaint.setAntiAlias(true);
//设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰
mPaint.setDither(true);
mBgPaint.setDither(true);
//设置画笔的样式:空心
mBgPaint.setStyle(Paint.Style.STROKE);
//设置画笔颜色
mBgPaint.setColor(mBgColor);
//旋转的时候大圆的半径不变,为初始化值
mCurrentRatationRadios = mRotationRadius;
//聚合后放大圆的初始半径为小圆半径
mScaleCircle = mCircleRadius;
//获取颜色数组,小圆的个数和定义颜色的个数相等
mCircleColors = context.getResources().getIntArray(R.array.circleColor);
if (mCircleColors.length > 0) {
//每个小圆之间的间隔角度(弧度)
mRotationAngle = (float) (2 * Math.PI / mCircleColors.length);
}
}
/**
* 获取view的中点坐标,view对角线长度的一半
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mCenterX = w / 2f;
mCenterY = h / 2f;
mDiagonalDist = (float) (Math.sqrt(w * w + h * h) / 2f);
}
@Override
protected void onDraw(Canvas canvas) {
//如果开始为空,则执行旋转动画
if (mState == null) {
mState = new RotationState();
}
//这边采用多态的方式,不断改变mState对象类型,执行不同的绘图动作
mState.drawState(canvas);
super.onDraw(canvas);
}
/**
* 数据加载完毕,关闭第一个动画,执行后面三个动画
*/
public void splashAndDisappear() {
//取消第一个动画
if (mState != null && mState instanceof RotationState) {
((RotationState) mState).cancel();
post(new Runnable() {
@Override
public void run() {
mState = new MergingState();
}
});
}
}
/**
* 旋转动画
*/
private class RotationState implements LoadState {
private ValueAnimator animator;
public RotationState() {
animator = ValueAnimator.ofFloat(0f, (float) (2 * Math.PI));
animator.setDuration(mRotationDuration);
//设置无限循环
animator.setRepeatCount(ValueAnimator.INFINITE);
//匀速旋转
animator.setInterpolator(new LinearInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//获取大圆旋转的当前角度
mCurrentRotationAngle = (float) animation.getAnimatedValue();
//重绘图像
invalidate();
}
});
animator.start();
}
@Override
public void drawState(Canvas canvas) {
clearCanvas(canvas);
darwCircle(canvas);
}
/**
* 取消旋转动画
*/
public void cancel() {
animator.cancel();
}
}
/**
* 绘制小圆
*
* @param canvas
*/
private void darwCircle(Canvas canvas) {
for (int i = 0; i < mCircleColors.length; i++) {
//设置画笔颜色
mPaint.setColor(mCircleColors[i]);
//小圆的x坐标
float cx = (float) (mCurrentRatationRadios * Math.cos(mCurrentRotationAngle + mRotationAngle * i) + mCenterX);
float cy = (float) (mCurrentRatationRadios * Math.sin(mCurrentRotationAngle + mRotationAngle * i) + mCenterY);
canvas.drawCircle(cx, cy, mCircleRadius, mPaint);
}
}
/**
* 清空画布
*
* @param canvas
*/
private void clearCanvas(Canvas canvas) {
//如果空心圆的半径为0,则清空画布,如果mHoleRadius不为零,说明正在执行扩散动画
if (mHoleRadius > 0f) {
//画笔的宽度
mBgPaint.setStrokeWidth(mDiagonalDist - mHoleRadius);
//空心圆的半径
float radius = mDiagonalDist / 2 + mHoleRadius / 2;
canvas.drawCircle(mCenterX, mCenterY, radius, mBgPaint);
} else {
canvas.drawColor(mBgColor);
}
}
/**
* 聚合动画
*/
private class MergingState implements LoadState {
private ValueAnimator animator;
public MergingState() {
animator = ValueAnimator.ofFloat(0f, mRotationRadius);
//开始有个弹射效果,输入的参数越大,弹射效果越明显
animator.setInterpolator(new OvershootInterpolator(6f));
animator.setDuration(mSplashDuration);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mCurrentRatationRadios = (float) animation.getAnimatedValue();
invalidate();
}
});
//反向计算
animator.reverse();
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
post(new Runnable() {
@Override
public void run() {
mState = new CircleStae();
}
});
}
});
}
@Override
public void drawState(Canvas canvas) {
clearCanvas(canvas);
darwCircle(canvas);
}
}
/**
* 圆缩放动画
*/
private class CircleStae implements LoadState {
private ValueAnimator animator;
public CircleStae() {
animator = ValueAnimator.ofFloat(mCircleRadius, 2.5f * mCircleRadius, mCircleRadius);
animator.setDuration(mSplashDuration);
animator.setInterpolator(new LinearInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//当前圆的圆心
mScaleCircle = (float) animation.getAnimatedValue();
//重绘图像
invalidate();
}
});
animator.start();
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
post(new Runnable() {
@Override
public void run() {
mState = new ExpandingStae();
}
});
}
});
}
@Override
public void drawState(Canvas canvas) {
clearCanvas(canvas);
canvas.drawCircle(mCenterX, mCenterY, mScaleCircle, mPaint);
}
}
/**
* 扩散动画
*/
private class ExpandingStae implements LoadState {
private ValueAnimator animator;
public ExpandingStae() {
animator = ValueAnimator.ofFloat(0, mDiagonalDist);
animator.setDuration(mSplashDuration);
//扩散我这边使用的是匀速,可以换成加速:AccelerateInterpolator
animator.setInterpolator(new LinearInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//获取空心圆的半径
mHoleRadius = (float) animation.getAnimatedValue();
//重绘图像
invalidate();
}
});
animator.start();
}
@Override
public void drawState(Canvas canvas) {
clearCanvas(canvas);
}
}
}

activity中执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class MdLoadActivity extends AppCompatActivity {
private LoadView loadView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SplashView splashView = new SplashView(MdLoadActivity.this);
ContentView contentView = new ContentView(MdLoadActivity.this);
loadView = new LoadView(this);
FrameLayout fl = new FrameLayout(this);
// fl.addView(splashView);
fl.addView(contentView);
fl.addView(loadView);
setContentView(fl);
handler.postDelayed(() -> loadView.splashAndDisappear(), 2000);
}
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};