移动架构21_动画框架源码分析

来源:互联网 发布:遥远的救世主 知乎 编辑:程序博客网 时间:2024/06/05 16:41
阅读本文时,请打开源码,跟着理解效果更好(22以上)
一、 初始化:ofFloat(imageView,"scaleX",of,1f)
动画几个启动元素的封装:控件、动画属性描述(平移还是缩放、x方向还是y方向)、过程(起始、过程、终止);它只是做了动画关键帧(KeyFrameSet)的解析
ss
(1)ObjectAnimator(extends ValueAnimator ):ofFloat
public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {ObjectAnimator anim = new ObjectAnimator(target, propertyName);anim.setFloatValues(values);return anim;    }
->ObjectAnimator:
private ObjectAnimator(Object target, String propertyName) {setTarget(target);setPropertyName(propertyName);}
->setPropertyName:
mPropertyName = propertyName;
只是将控件View传递进来,并将propertyName赋值;回到ofFloat方法:
anim.setFloatValues(values);
(2)setFloatValues:
public void setFloatValues(float... values) {      if (mValues == null || mValues.length == 0) { if (mProperty != null) {    setValues(PropertyValuesHolder.ofFloat(mProperty, values));    } else {   setValues(PropertyValuesHolder.ofFloat(mPropertyName, values));         } else {            super.setFloatValues(values);      }    }


mValues为null,mProperty ==null;
-> setValues(PropertyValuesHolder.ofFloat(mPropertyName, values))
//实例化FloateProtyValuesHodler

(3) PropertyValuesHolder 封装了动画的每一帧和动画执行类
public static PropertyValuesHolder ofFloat(String propertyName, float... values) {
return new FloatPropertyValuesHolder(propertyName, values);
}

//FloatPropertyValuesHolder是PropertyValuesHolder的子类
public FloatPropertyValuesHolder(Property property, float... values) {       super(property);      setFloatValues(values);     if (property instanceof FloatProperty) {      mFloatProperty = (FloatProperty) mProperty;     }
//super(property):mPropertyName = property.getName();(就是做什么动画,平移还是缩放)
->setFloatValues:

(4)FloatPropertyValuesHolder.setFloatValues:( 可变参数的关键帧)

public void setFloatValues(float... values) {
super.setFloatValues(values);
mFloatKeyframes = (Keyframes.FloatKeyframes) mKeyframes;
}

a) super.setFloatValues(values)=>PropertyValuesHolder.setFloatValues
public void setFloatValues(float... values) {
mValueType = float.class;
mKeyframes = KeyframeSet.ofFloat(values);
//生成了Keyframe集合,为了解耦合,每一帧动画与PropertyValuesHolder分开
}
b)KeyframeSet.ofFloat实例化一帧,将参数进行封装
...
if (numKeyframes == 1) {
keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f);
keyframes[1] = (FloatKeyframe) Keyframe.ofFloat(1f, values[0]);
if (Float.isNaN(values[0])) {
badValue = true;
}
} else {
keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f, values[0]);
for (int i = 1; i < numKeyframes; ++i) {
keyframes[i] =
(FloatKeyframe) Keyframe.ofFloat((float) i / (numKeyframes - 1), values[i]);
if (Float.isNaN(values[i])) {
badValue = true;
}
}
}
//如果传一个,则从0开始,有两帧
...
return new FloatKeyframeSet(keyframes);

FloatKeyframeSet=>KeyframeSet=>KeyframeSet:List<Keyframe> mKeyframes;
mKeyframes是保存每一帧的集合

流程图:
ss

2. ObjectAnimator初始化的一些方法
setDuration设置时间
setInterpolator设置插值器
setRepeatCount设置重复次数,-1表示无线

二、ValueAnimator:start 开启动画
属性动画最终调用的setX、setWidth等等方法,调用重绘方法
开启动画的核心;如果2中的方法放到start后面,是不能生效的;
关键:线程 + 队列 +类似setX\setWidth的方法
ss
1)首先调用子类start,后调用父类start方法
->AnimationHandler animationHandler = AnimationHandler.getInstance();
animationHandler.addAnimationFrameCallback(this, (long) (mStartDelay * sDurationScale));
//每隔16ms进行一次回调


this:ValueAnimator可以传入,说明其实现了接口AnimationFrameCallback
AnimationFrameCallback有doAnimationFrame和commitAnimationFrame方法, doAnimationFrame是隔16ms(VSYNC信号触发:用于绘制)调用
注意:不同版本的代码具体实现不同,但都是获取AnimationHandler对象,当前Animator实现一个回调方法,传入到AnimationHandler中去,回调方法会被不断执行。

2)ValueAnimator重写了doAnimationFrame方法(不断被调用)。
-》animateBasedOnTime(currentTime)// 计算动画执行百分比。参数为绝对时间
一些Listener的回调(观察者模式):
for (int i = 0; i < numListeners; ++i) {
mListeners.get(i).onAnimationRepeat(this);
}

-》animateValue(currentIterationFraction);
注意:ValueAnimator和ObjectAnimator都有animateValue方法,此处调用的是子类的animateValue方法,currentIterationFraction:0-1;

3) ObjectAnimator.animateValue()
...
super.animateValue(fraction);
a)//调用了父类的animateValue,为当前方法的后面做了铺垫
if (mUpdateListeners != null) {
int numListeners = mUpdateListeners.size();
for (int i = 0; i < numListeners; ++i) {
mUpdateListeners.get(i).onAnimationUpdate(this);
}
}

b)-》ValueAnimator.animateValue:
//得到插值器变化的百分比
fraction = mInterpolator.getInterpolation(fraction);
//ValueAnimator是环境角色、动画设置插值器方法传入的对象如LinearInterpolator是具体的策略决策,而其实现的接口TimeInterpolator是抽象策略决策,TimeInterpolator的方法TimeInterpolator是策略方法(传入一个百分比,返回一个百分比)
线性插值器:LinearInterpolator
public float getInterpolation(float input) {
return input;
}

加速插值器:AccelerateInterpolator
public float getInterpolation(float input) {
if (mFactor == 1.0f) {
return input * input;
} else {
return (float)Math.pow(input, mDoubleFactor);
}
}

c)返回到ValueAnimator.animateValue方法中:

for (int i = 0; i < numValues; ++i) {
mValues[i].calculateValue(fraction);
}
mValues的类型是PropertyValuesHolder
->PropertyValuesHolder.calculateValue
Object value = mKeyframes.getValue(fraction);
mAnimatedValue = mConverter == null ? value : mConverter.co
//mAnimatedValue 保存当前执行的百分比

ValueAnimator.animateValue继续执行:
if (mUpdateListeners != null) {
int numListeners = mUpdateListeners.size();
for (int i = 0; i < numListeners; ++i) {
mUpdateListeners.get(i).onAnimationUpdate(this);
}
}
//addUpdateListener的回调方法,观察者模式

d)父类的animateValue执行完了,返回到ObjectAnimator的animateValue方法中去,继续执行代码:
int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
mValues[i].setAnimatedValue(target);
}
//(PropertyValuesHolder)setAnimatedValue真正设置控件的宽高

e)PropertyValuesHolder.setAnimatedValue: 通过mSetter这个Method对象反射的方式设置控件宽高
...
mTmpValueArray[0] = getAnimatedValue();//返回的是上面设置的mAnimatedValue
mSetter.invoke(target, mTmpValueArray);//mSetter是Method类型,动画类型
//mSetter相当于“setScaleX”是View的方法


三、mSetter的设置
回到ValueAnimator的start(boolean)方法中:
startAnimation
-> initAnimation(子类ObjectAnimator重写了initAnimation方法)
而ObjectAnimator的initAnimation方法又调用了父类的initAnimation方法
mValues[i].setupSetterAndGetter(target);//mValues是PropertyValuesHolder类型
...
super.initAnimation();
//mValues在ValueAnimator中声明

PropertyValuesHolder.setupSetterAndGetter
其实调用的是子类:FloatPropertyValuesHolder的setupSetterAndGetter方法
->setupSetterOrGetter//将成员变量mSetter赋值
->getPropertyFunction(返回一个Method对象)
-》returnVal = targetClass.getMethod(methodName, args);//通过反射拿到了method

四、版本区别:
20版本以后AnimationHandler是单例的
AnimationHandler animationHandler = AnimationHandler.getInstance();
animationHandler.addAnimationFrameCallback(this, (long) (mStartDelay * sDurationScale));
->getProvider().postFrameCallback(mFrameCallback);

五、Vsync
当Vsync信号发出的时候 会回调mFrameCallback对象中的doFrame

六、属性动画调用原理
scaleX:是不断调用setScaleX
View.setScaleX(1)-> View.setScaleX(0.9)-> View.setScaleX(0.8) -> View.setScaleX(0.7)

七、Android手机卡顿的原因
  大多数用户感知到的卡顿等性能问题的最主要根源都是因为渲染性能。从设计师的角度,他们希望App能够有更多的动画,图片等时尚元素来实现流畅的用户体验。但是Android系统很有可能无法及时完成那些复杂的界面渲染操作。Android系统每隔16ms发出VSYNC信号,触发对UI进行渲染,如果每次渲染都成功,这样就能够达到流畅的画面所需要的60fps,为了能够实现60fps,这意味着程序的大多数操作都必须在16ms内完成。
draw_per_16ms
 
八、Choreographer机制,  用于同Vsync机制配合,实现统一调度界面绘图

注意:动画框架源码分析的难点在于,通常会用父类或接口来接收子类的实例,而同时子类又重写父类的方法,然后在方法里面手动调用父类的方法,如animateValue、initAnimation等方法,一定要看清到底是父类调用还是子类调用,此处一般是:父类声明接收子类、子类重写方法并调用该方法、子类方法中手动调用父类方法










原创粉丝点击