应用开发中常会用到动画,我们也会经常用到动画(帧动画,补间动画,属性动画),但是可能很多人都不知道动画在什么地方绘制,怎么绘制的?知道这些后我们才能更加得心应手去使用它。
一, 动画基本组件
一, 动画基本组件
(1),Animation 动画定义,包含动画相关配置信息(开始时间,执行间隔,重复等等), 用到插间器Interpolator, Transfromation动画转化状态
(2)Interpolator 插间器:用于定义控制动画的变化,是否平缓,加速,减速等
(3) Transformation 动画转化状态, 结合插间器计算的当前状态的值,产生当次动画实际需要的转化结果(包含Matrix, 以及alpa等)。
二,动画绘制流程
说明:在子视图本身加载动画的时候,我们应该发现,动画的作用范围是依赖父视图的,因此动画实际是在父视图容器内绘制。
下面进入正题贴图:
动画绘制分两个步骤:
1, 如何分发到animation
(1)通过 view.startAnimation调用动画
public void startAnimation(Animation animation) { animation.setStartTime(Animation.START_ON_FIRST_FRAME); setAnimation(animation); invalidateParentCaches(); invalidate(true); }
做了两件事,第一件清除父视图的缓存,让父视图绘制,调用自身局部刷新。(invalidate局部刷新会最终调用viewroot去分发,最终会遍历视图层级,绘制指定区域。而清除父视图缓存则让父视图在遍历过程支持重新创建绘制,这也就是说明动画绘制实际是依赖父视图内部绘制)
( 2 )绘制分发必然会走到 draw 方法,而父视图在处理时会 dipatchDraw 分发给子视图做进一步绘制。最终调到子视图 draw(canvas , parent, drawTime) ,最终我们发现 drawAnimation(Parent...) 。返回 more 则判断是否需要继续执行动画,boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) { boolean useDisplayListProperties = mAttachInfo != null && mAttachInfo.mHardwareAccelerated; boolean more = false; parent.mChildTransformation.clear Transformation transformToApply = null; final Animation a = getAnimation(); if (a != null) { more = drawAnimation(parent, drawingTime, a, scalingRequired); ..return more }2 , Animation 执行
private boolean drawAnimation(ViewGroup parent, long drawingTime,
Animation a, boolean scalingRequired) {
Transformation invalidationTransform;
final int flags = parent.mGroupFlags;
final boolean initialized = a.isInitialized();
if (!initialized) {
a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight());
a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop);
if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler);
onAnimationStart();
}
boolean more = a.getTransformation(drawingTime, parent.mChildTransformation, 1f);
if (scalingRequired && mAttachInfo.mApplicationScale != 1f) {
if (parent.mInvalidationTransformation == null) {
parent.mInvalidationTransformation = new Transformation();
}
invalidationTransform = parent.mInvalidationTransformation;
a.getTransformation(drawingTime, invalidationTransform, 1f);
} else {
invalidationTransform = parent.mChildTransformation;
}
if (more) {
if (!a.willChangeBounds()) {
if ((flags & (ViewGroup.FLAG_OPTIMIZE_INVALIDATE | ViewGroup.FLAG_ANIMATION_DONE)) ==
ViewGroup.FLAG_OPTIMIZE_INVALIDATE) {
parent.mGroupFlags |= ViewGroup.FLAG_INVALIDATE_REQUIRED;
} else if ((flags & ViewGroup.FLAG_INVALIDATE_REQUIRED) == 0) {
// The child need to draw an animation, potentially offscreen, so
// make sure we do not cancel invalidate requests
parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION;
parent.invalidate(mLeft, mTop, mRight, mBottom);
}
} else {
if (parent.mInvalidateRegion == null) {
parent.mInvalidateRegion = new RectF();
}
final RectF region = parent.mInvalidateRegion;
a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region,
invalidationTransform);
// The child need to draw an animation, potentially offscreen, so
// make sure we do not cancel invalidate requests
parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION;
final int left = mLeft + (int) region.left;
final int top = mTop + (int) region.top;
parent.invalidate(left, top, left + (int) (region.width() + .5f),
top + (int) (region.height() + .5f));
}
}
return more;
}
主要是这样的:首先会通过Animation.getTransformation(outTransform..)将当前时刻需要的动画转化信息获取, 而当前转化信息包含Matrix变化,以及alpa透明度。 Transformation获取的过程依赖 Interpolator插间器(内部计算动画变化趋势)确定。并且记录在
parent.mChildTransformation
后续Canvas根据transformation进行绘制。
后续Canvas根据transformation进行绘制。