@@ -179,13 +179,17 @@ UML类图
179
179
180
180
Interpolator mInterpolator;
181
181
public boolean getTransformation(long currentTime, Transformation outTransformation) {
182
- //计算处理 ...
182
+ //计算处理当前动画的时间点 ...
183
183
final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime);
184
+ //后续处理,以此来应用动画效果...
184
185
applyTransformation(interpolatedTime, outTransformation);
185
- //后续处理...
186
- return mMore;
186
+ return mMore;
187
187
}
188
188
189
+ 默认是不做任何操作,由具体的子类动画来实现操作,可见附加分析里的操作。
190
+
191
+ protected void applyTransformation(float interpolatedTime, Transformation t) {
192
+ }
189
193
190
194
## 4. 杂谈
191
195
策略模式主要用来分离算法,根据相同的行为抽象来做不同的具体策略实现。
@@ -202,5 +206,190 @@ UML类图
202
206
203
207
* 随着策略的增加,子类也会变得繁多。
204
208
209
+ ## 5.附加:Android 动画实现的基本原理解析
210
+
211
+ Android中最简单的动画就是Tween Animation了,当然帧动画和属性动画也挺方便的,但是基本原理都类似,毕竟动画的本质都是一帧一帧的展现给用户的,只不要当fps小于60的时候,人眼基本看不出间隔,也就成了所谓的流畅动画。(注:属性动画是3.0以后才有的,低版本可采用[ NineOldAndroids] ( https://github.com/JakeWharton/NineOldAndroids ) 来兼容。
205
212
213
+ 首先要想知道动画的执行流程,还是得从View入手,因为Android中主要针对的操作对象还是View,所以我们首先到View中查找,我们找到了View.startAnimation(Animation animation)这个方法
214
+
215
+ public void startAnimation(Animation animation) {
216
+ //初始化动画开始时间
217
+ animation.setStartTime(Animation.START_ON_FIRST_FRAME);
218
+ //对View设置动画
219
+ setAnimation(animation); //赋值到-->mCurrentAnimation
220
+ //刷新父类缓存
221
+ invalidateParentCaches();
222
+ //刷新View本身及子View
223
+ invalidate(true);
224
+ }
225
+
226
+ 考虑到View一般不会单独存在,都是存在于某个ViewGroup中,所以google使用动画绘制的地方选择了在ViewGroup中的drawChild(Canvas canvas, View child, long drawingTime)方法中进行调用子View的绘制。
227
+
228
+ protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
229
+ return child.draw(canvas, this, drawingTime);
230
+ }
231
+
232
+ 再看下View中的draw(Canvas canvas, ViewGroup parent, long drawingTime)方法中是如何调用使用Animation的
206
233
234
+ boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
235
+ //...
236
+
237
+ //查看是否需要清除动画信息
238
+ final int flags = parent.mGroupFlags;
239
+ if ((flags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) == ViewGroup.FLAG_CLEAR_TRANSFORMATION) {
240
+ parent.getChildTransformation().clear();
241
+ parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION;
242
+ }
243
+
244
+ //获取设置的动画信息
245
+ final Animation a = getAnimation();
246
+ if (a != null) {
247
+ //绘制动画
248
+ more = drawAnimation(parent, drawingTime, a, scalingRequired);
249
+ concatMatrix = a.willChangeTransformationMatrix();
250
+ if (concatMatrix) {
251
+ mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM;
252
+ }
253
+ transformToApply = parent.getChildTransformation();
254
+ } else {
255
+ //...
256
+ }
257
+ }
258
+
259
+ 可以看出在父类调用View的draw方法中,会先判断是否设置了清除到需要做该表的标记,然后再获取设置的动画的信息,如果设置了动画,就会调用View中的drawAnimation方法,具体如下:
260
+
261
+ private boolean drawAnimation(ViewGroup parent, long drawingTime,
262
+ Animation a, boolean scalingRequired) {
263
+
264
+ Transformation invalidationTransform;
265
+ final int flags = parent.mGroupFlags;
266
+ //判断动画是否已经初始化过
267
+ final boolean initialized = a.isInitialized();
268
+ if (!initialized) {
269
+ a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight());
270
+ a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop);
271
+ if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler);
272
+ onAnimationStart();
273
+ }
274
+
275
+ //判断View是否需要进行缩放
276
+ final Transformation t = parent.getChildTransformation();
277
+ boolean more = a.getTransformation(drawingTime, t, 1f);
278
+ if (scalingRequired && mAttachInfo.mApplicationScale != 1f) {
279
+ if (parent.mInvalidationTransformation == null) {
280
+ parent.mInvalidationTransformation = new Transformation();
281
+ }
282
+ invalidationTransform = parent.mInvalidationTransformation;
283
+ a.getTransformation(drawingTime, invalidationTransform, 1f);
284
+ } else {
285
+ invalidationTransform = t;
286
+ }
287
+
288
+ if (more) {
289
+ //根据具体实现,判断当前动画类型是否需要进行调整位置大小,然后刷新不同的区域
290
+ if (!a.willChangeBounds()) {
291
+ //...
292
+
293
+ }else{
294
+ //...
295
+ }
296
+ }
297
+ return more;
298
+ }
299
+ 其中主要的操作是动画始化、动画操作、界面刷新。动画的具体实现是调用了Animation中的getTransformation(long currentTime, Transformation outTransformation,float scale)方法,该方式主要是获取缩放系数。
300
+
301
+ public boolean getTransformation(long currentTime, Transformation outTransformation,
302
+ float scale) {
303
+ mScaleFactor = scale;
304
+ return getTransformation(currentTime, outTransformation);
305
+ }
306
+
307
+ 在上面的方法中,又调用了插值器中分析提到的方法: Animation.getTransformation(long currentTime, Transformation outTransformation),分析至此……大致就先这样吧。
308
+
309
+
310
+
311
+ 最后来看一下Animation类的结构:
312
+
313
+ ![ url] ( images/strategy-kerison-uml-android-animation.png )
314
+
315
+ 可以看出Animation的直接父类就是Object,直接子类除了AnimationSet(多个动画组成的一组动画效果,归根结底还是动画),其他几个子类都是Android内置的简单动画类型,从上面对插值器的分析中可以看出,Animation会调用applyTransformation来应用动画时间来达到动态效果。
316
+
317
+ 例如:
318
+
319
+ 1 . AlphaAnimation 主要是针对View的alpha属性根据时间做了动态调整:
320
+
321
+ @Override
322
+ protected void applyTransformation(float interpolatedTime, Transformation t) {
323
+ final float alpha = mFromAlpha;
324
+ t.setAlpha(alpha + ((mToAlpha - alpha) * interpolatedTime));
325
+ }
326
+
327
+ 2 . RotateAnimation 主要是针对View Matrix的角度值根据时间做了动态调整。
328
+
329
+ @Override
330
+ protected void applyTransformation(float interpolatedTime, Transformation t) {
331
+ float degrees = mFromDegrees + ((mToDegrees - mFromDegrees) * interpolatedTime);
332
+ float scale = getScaleFactor();
333
+ //判断是否设置旋转中心
334
+ if (mPivotX == 0.0f && mPivotY == 0.0f) {
335
+ t.getMatrix().setRotate(degrees);
336
+ } else {
337
+ t.getMatrix().setRotate(degrees, mPivotX * scale, mPivotY * scale);
338
+ }
339
+ }
340
+ 3 . ScaleAnimation 主要是针对View Matrix的缩放值根据时间做了动态调整。
341
+
342
+ @Override
343
+ protected void applyTransformation(float interpolatedTime, Transformation t) {
344
+ float sx = 1.0f;
345
+ float sy = 1.0f;
346
+ float scale = getScaleFactor();
347
+ //判断X方向是否需要调整
348
+ if (mFromX != 1.0f || mToX != 1.0f) {
349
+ sx = mFromX + ((mToX - mFromX) * interpolatedTime);
350
+ }
351
+ //判断Y方向是否需要做调整
352
+ if (mFromY != 1.0f || mToY != 1.0f) {
353
+ sy = mFromY + ((mToY - mFromY) * interpolatedTime);
354
+ }
355
+ //判断是否设置缩放中心
356
+ if (mPivotX == 0 && mPivotY == 0) {
357
+ t.getMatrix().setScale(sx, sy);
358
+ } else {
359
+ t.getMatrix().setScale(sx, sy, scale * mPivotX, scale * mPivotY);
360
+ }
361
+ }
362
+ 4 . TranslatieAnimation 主要是针对View Matrix的位移值根据时间做了动态调整。
363
+
364
+ @Override
365
+ protected void applyTransformation(float interpolatedTime, Transformation t) {
366
+ float dx = mFromXDelta;
367
+ float dy = mFromYDelta;
368
+ //判断X方向是否需要调整
369
+ if (mFromXDelta != mToXDelta) {
370
+ dx = mFromXDelta + ((mToXDelta - mFromXDelta) * interpolatedTime);
371
+ }
372
+ //判断Y方向是否需要做调整
373
+ if (mFromYDelta != mToYDelta) {
374
+ dy = mFromYDelta + ((mToYDelta - mFromYDelta) * interpolatedTime);
375
+ }
376
+ t.getMatrix().setTranslate(dx, dy);
377
+ }
378
+ 5 . 自定义一个简单的Animation,一般主要实现applyTransformation对View根据interpolatedTime做动态调整即可,稍微复杂点的可以添加额外操作。
379
+
380
+ Animation animation = new Animation() {
381
+ @Override
382
+ protected void applyTransformation(float interpolatedTime,
383
+ Transformation t) {
384
+ // TODO Auto-generated method stub
385
+ super.applyTransformation(interpolatedTime, t);
386
+ //对alpha进行操作
387
+ //t.setAlpha(alpha)
388
+ //对matrix进行操作
389
+ //t.getMatrix().set ...
390
+ }
391
+ };
392
+ matrix的一系列操作:
393
+ ![ url] ( images/strategy-kerison-uml-android-animation-matrix.png )
394
+
395
+ 当然复杂的动画可以需要进行更多的效果计算和方式组合,例如属性动画中可以自定义View的新属性,但是本质都是一样的,就说这么多吧,还望牛人路过支点。
0 commit comments