Skip to content

Commit 894a231

Browse files
committedMar 11, 2015
extra analysis for animation in animation
1 parent a41697a commit 894a231

File tree

4 files changed

+195
-15
lines changed

4 files changed

+195
-15
lines changed
 

‎strategy/README.md‎

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,4 @@
11
# 任务表
2-
| 作者 | 预计完成时间 |
3-
| ------------- |:-------------: |
4-
| GKerison | 2015.3.6 |
5-
6-
7-
8-
9-
10-
11-
12-
13-
2+
| 作者 |预计完成时间 |
3+
| ------------- |:---------------------:|
4+
| GKerison | 2015.3.15 |

‎strategy/gkerison/README.md‎

Lines changed: 192 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -179,13 +179,17 @@ UML类图
179179

180180
Interpolator mInterpolator;
181181
public boolean getTransformation(long currentTime, Transformation outTransformation) {
182-
//计算处理...
182+
//计算处理当前动画的时间点...
183183
final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime);
184+
//后续处理,以此来应用动画效果...
184185
applyTransformation(interpolatedTime, outTransformation);
185-
//后续处理...
186-
return mMore;
186+
return mMore;
187187
}
188188

189+
默认是不做任何操作,由具体的子类动画来实现操作,可见附加分析里的操作。
190+
191+
protected void applyTransformation(float interpolatedTime, Transformation t) {
192+
}
189193

190194
## 4. 杂谈
191195
策略模式主要用来分离算法,根据相同的行为抽象来做不同的具体策略实现。
@@ -202,5 +206,190 @@ UML类图
202206

203207
* 随着策略的增加,子类也会变得繁多。
204208

209+
## 5.附加:Android 动画实现的基本原理解析
210+
211+
Android中最简单的动画就是Tween Animation了,当然帧动画和属性动画也挺方便的,但是基本原理都类似,毕竟动画的本质都是一帧一帧的展现给用户的,只不要当fps小于60的时候,人眼基本看不出间隔,也就成了所谓的流畅动画。(注:属性动画是3.0以后才有的,低版本可采用[NineOldAndroids](https://github.com/JakeWharton/NineOldAndroids)来兼容。
205212

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的
206233

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的新属性,但是本质都是一样的,就说这么多吧,还望牛人路过支点。
26.3 KB
Loading
8.95 KB
Loading

0 commit comments

Comments
 (0)
Please sign in to comment.