public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) public static <T> ObjectAnimator ofFloat(T target, Property<T, Float> property, float... values) public static ObjectAnimator ofInt(Object target, String propertyName, int... values) public static <T> ObjectAnimator ofInt(T target, Property<T, Integer> property, int... values) public static ObjectAnimator ofObject(Object target, String propertyName, TypeEvaluator evaluator, Object... values) public static <T, V> ObjectAnimator ofObject(T target, Property<T, V> property, TypeEvaluator<V> evaluator, V... values) public static ObjectAnimator ofPropertyValuesHolder(Object target, PropertyValuesHolder... values)
public void setTarget(Object target) 设置目标对象 public ObjectAnimator setDuration(long duration) 设置持续时间 public void setProperty(Property property) 设置属性 public void setPropertyName(String propertyName) 设置属性名称 public void setIntValues(int... values) 设置Int值,对应ObjectAnimator.ofInt public void setFloatValues(float... values) 设置Float,对应ObjectAnimator.ofFloat public void setObjectValues(Object... values) 设置Object值,对应ObjectAnimator.ofObject
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(img, "translationX", 0.0f, 350.0f, 0f); objectAnimator.setDuration(2000);//动画时间 objectAnimator.setInterpolator(new BounceInterpolator());//动画插值 objectAnimator.setRepeatCount(-1);//设置动画重复次数 objectAnimator.setRepeatMode(ValueAnimator.RESTART);//动画重复模式 objectAnimator.setStartDelay(1000);//动画延时执行 objectAnimator.start();//启动动画 objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){ @Override public void onAnimationUpdate(ValueAnimator animation){ //根据变化值来设置imageView对象的Y轴坐标,这样就实现了imageView的垂直移动 // img.setTranslationY((Float) animation.getAnimatedValue()); } }); objectAnimator.addListener(new Animator.AnimatorListener() { //动画开始 @Override public void onAnimationStart(Animator animation) { } //动画结束 @Override public void onAnimationEnd(Animator animation) { } //动画取消 @Override public void onAnimationCancel(Animator animation) { } //动画重复 @Override public void onAnimationRepeat(Animator animation) { } }); objectAnimator.addPauseListener(new Animator.AnimatorPauseListener() { //动画暂停 @Override public void onAnimationPause(Animator animation) { } //动画重启 @Override public void onAnimationResume(Animator animation) { } });
下面总结一下:
(1). objectObjectAnimator必须要提供setXxx方法,如果动画的时候没有传递初始值,那么还要提供getXxx方法,因为系统要去拿xxx属性的初始值。
(2). 另外设置属性值之后,应该使用requestLayout()或者invalidate()去进行刷新操作,这样才能看到动画效果。
当我们需要对某个对象的属性进行动画,但是这个属性没有提供对应的getXxx()、setXxx()方法该怎么办,我们有三种方法可以做:
a:给你的对象加上get和set方法,如果你有权限的话
b:用一个类来包装原始对象,间接为其提供get和set方法
c:采用ValueAnimator,监听动画过程,自己实现属性的改变
另外,我们我们看到每一种动画属性都有两种方式一种是指定属性名,一种是指定一个Property对象,它对应的就是我们的自定义属性。假如我们希望更改我们自定义的某个属性,我们就可以使用这个,原理是相同的,就是不断的修改对应的属性值,下面来举个例子,假如我们自定义了一个圆,我们希望这个圆可以做一个动画就是半径可以指定的范围内进行变化。
<resources> <declare-styleable name="CircleAnim"> <attr name="pivotX" format="dimension"/> <attr name="pivotY" format="dimension"/> <attr name="radius" format="dimension"/> declare-styleable> resources>
public class CircleAnim extends View { private float mPivotX; private float mPivotY; private float mRadius; private Paint mPaint; public CircleAnim(Context context) { this(context, null); } public CircleAnim(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CircleAnim(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CircleAnim); mPivotX = ta.getDimension(R.styleable.CircleAnim_pivotX, 0); mPivotY = ta.getDimension(R.styleable.CircleAnim_pivotY, 0); mRadius = ta.getDimension(R.styleable.CircleAnim_radius, 0); ta.recycle(); init(); } private void init() { mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setStrokeWidth(5); mPaint.setColor(Color.parseColor("#0F000F")); } public void setRadius(float radius) { mRadius = radius; invalidate(); } public float getRadius() { return mRadius; } @Override protected void onDraw(Canvas canvas) { canvas.drawCircle(mPivotX, mPivotY, mRadius, mPaint); super.onDraw(canvas); } }
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:gravity="center" android:layout_width="match_parent" android:layout_height="match_parent"> <com.eric.windows.anima.CircleAnim android:id="@+id/circle" app:pivotX="150dp" app:pivotY="100dp" android:layout_width="wrap_content" android:layout_height="wrap_content" /> LinearLayout>
public class MainActivity extends AppCompatActivity { private CircleAnim mCircleAnim; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mCircleAnim = (CircleAnim) findViewById(R.id.circle); final ObjectAnimator animator = ObjectAnimator.ofFloat(mCircleAnim, new RadiusProperty(CircleAnim.class, "CircleAnim"), 0, dp2px(40)); animator.setDuration(5000); findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { animator.start(); } }); } private float dp2px(float dp) { return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics()); } }
class RadiusProperty extends Property<CircleAnim, Float> { public RadiusProperty(Class type, String name) { super(type, name); } @Override public Float get(CircleAnim object) { return object.getRadius(); } @Override public void set(CircleAnim object, Float value) { object.setRadius(value); } }
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(img, "translationX", 0.0f, 350.0f, 0f); objectAnimator.setDuration(2000);//动画时间 objectAnimator.setInterpolator(new BounceInterpolator());//动画插值 objectAnimator.setRepeatCount(-1);//设置动画重复次数 objectAnimator.setRepeatMode(ValueAnimator.RESTART);//动画重复模式 objectAnimator.setStartDelay(1000);//动画延时执行 objectAnimator.start();//启动动画
public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) { ObjectAnimator anim = new ObjectAnimator(target, propertyName); anim.setFloatValues(values); return anim; }
private Property mProperty; public void setFloatValues(float... values) { if (mValues == null || mValues.length == 0) { // No values yet - this animator is being constructed piecemeal. Init the values with // whatever the current propertyName is if (mProperty != null) {//mProperty 不为null,直接使用mProperty setValues(PropertyValuesHolder.ofFloat(mProperty, values)); } else {//否则的话,必须指定属性名 setValues(PropertyValuesHolder.ofFloat(mPropertyName, values)); } } else { super.setFloatValues(values); } }
public static <T> ObjectAnimator ofFloat(T target, Property<T, Float> property, float... values)
Method mSetter = null; private Method mGetter = null;
void setupSetter(Class targetClass) { Class> propertyType = mConverter == null ? mValueType : mConverter.getTargetType(); mSetter = setupSetterOrGetter(targetClass, sSetterPropertyMap, "set", propertyType); } private void setupGetter(Class targetClass) { mGetter = setupSetterOrGetter(targetClass, sGetterPropertyMap, "get", null); }
说明,好,到这里知道了set、get的方法是怎么来的,那么它们又是怎么被调用的呐?只能继续找mSetter、mGetter相关内容了,找来找去发现private Method setupSetterOrGetter(Class targetClass, HashMap<Class, HashMap<String, Method>> propertyMapMap, String prefix, Class valueType) { Method setterOrGetter = null; synchronized(propertyMapMap) { //如果propertyMap中已经存在这个方法那么直接拿来使用吧 HashMap<String, Method> propertyMap = propertyMapMap.get(targetClass); boolean wasInMap = false; if (propertyMap != null) { wasInMap = propertyMap.containsKey(mPropertyName); if (wasInMap) { setterOrGetter = propertyMap.get(mPropertyName); } } if (!wasInMap) { //在这里调用getPropertyFunction通过反射机制取得我们需要函数,具体怎么得到的咱就不淘汰 setterOrGetter = getPropertyFunction(targetClass, prefix, valueType); if (propertyMap == null) { propertyMap = new HashMap<String, Method>(); propertyMapMap.put(targetClass, propertyMap); }//把获取的get/set保存到propertyMap集合中 其实是保存到了成员变量sSetterPropertyMap中 propertyMap.put(mPropertyName, setterOrGetter); } } return setterOrGetter; }
mSetter、mGetter只调用下面这个函数:
public native Object invoke(Object receiver, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException;
public class A { public void foo(String name) { System.out.println("Hello, " + name); } }
import java.lang.reflect.Method; public class TestClassLoad { public static void main(String[] args) throws Exception { Class> clz = Class.forName("A"); Object o = clz.newInstance(); Method m = clz.getMethod("foo", String.class); for (int i = 0; i < 5; i++) { m.invoke(o, Integer.toString(i)); } }
Hello, 0
Hello, 1
Hello, 2
Hello, 3
Hello, 4
public static <T> ObjectAnimator ofFloat(T target, Property<T, Float> property, float... values)
CircleAnim mCircleAnim = (CircleAnim) findViewById(R.id.circle); final ObjectAnimator animator2 = ObjectAnimator.ofFloat(mCircleAnim, new FloatProperty<CircleAnim>("pivotX") { @Override public void setValue(CircleAnim object, float value) { object.setRadius(value); } @Override public Float get(CircleAnim object) { return object.getRadius(); } }, 0, 100); animator.setDuration(5000); findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { animator2.start(); } });
public abstract class FloatProperty<T> extends Property<T, Float> { public FloatProperty(String name) { super(Float.class, name); } public abstract void setValue(T object, float value) @Override final public void set(T object, Float value) { setValue(object, value); } }
public static <T> ObjectAnimator ofFloat(T target, Property<T, Float> property, float... values) { //调用ObjectAnimator的构造函数创建一个ObjectAnimator实例,在这个构造函数中又调用了setProperty函数来保存property ObjectAnimator anim = new ObjectAnimator(target, property); //设置属性值 anim.setFloatValues(values); return anim; }
public void setFloatValues(float... values) { if (mValues == null || mValues.length == 0) { if (mProperty != null) {//此时mProperty 不为null,走这里 setValues(PropertyValuesHolder.ofFloat(mProperty, values)); } else { ..... } } else { ..... } }
protected Property mProperty; public static PropertyValuesHolder ofFloat(Property, Float> property, float... values) { //创建一个FloatPropertyValuesHolder实例,其为PropertyValuesHolder子类,它们的关系如Property、FloatProperty的关系 return new FloatPropertyValuesHolder(property, values); } public FloatPropertyValuesHolder(Property property, float... values) { super(property);//调用父类的构造方法 ...... } private PropertyValuesHolder(Property property) { mProperty = property;//把property保存到PropertyValuesHolder的成员变量mProperty上 ...... }
private void setupValue(Object target, Keyframe kf) { if (mProperty != null) { ////mProperty不为null 调用mProperty 的get方法 Object value = convertBack(mProperty.get(target)); kf.setValue(value); } else { try { if (mGetter == null) { Class targetClass = target.getClass(); setupGetter(targetClass);//mSetter为null则调用setupGetter函数查找get函数,上文已经说过 if (mGetter == null) { //找不到get函数,证明ObjectAnimator作用对象的属性没有get方法,那么将会造成动画无效, // 这也是为什么要强调:ObjectAnimator作用对象的属性必须有get、set方法的原因。 return; } } //找到get函数 通过mGetter调用invoke函数,间接调用mProperty的get方法,上文已经分析过 Object value = convertBack(mGetter.invoke(target)); ...... } catch (InvocationTargetException e) { ...... } catch (IllegalAccessException e) { ...... } } }
void setupSetterAndGetter(Object target) { ...... if (mProperty != null) { try { ...... for (int i = 0; i < keyframeCount; i++) { Keyframe kf = keyframes.get(i); if (!kf.hasValue() || kf.valueWasSetOnStart()) { if (testValue == null) { //mProperty不为null 调用mProperty 的get方法 testValue = convertBack(mProperty.get(target)); } ...... } } return; } catch (ClassCastException e) { ...... } } if (mProperty == null) {//mProperty为null 则要使用mSetter了 Class targetClass = target.getClass(); if (mSetter == null) {//mSetter为null则调用setupSetter函数查找set函数,上文已经说过 setupSetter(targetClass); } ...... for (int i = 0; i < keyframeCount; i++) { Keyframe kf = keyframes.get(i); if (!kf.hasValue() || kf.valueWasSetOnStart()) { if (mGetter == null) {//mSetter为null则调用setupGetter函数查找get函数,上文已经说过 setupGetter(targetClass); if (mGetter == null) { //找不到get函数,证明ObjectAnimator作用对象的属性没有get方法,那么将会造成动画无效, // 这也是为什么要强调:ObjectAnimator作用对象的属性必须有get、set方法的原因。 return; } } try {//找到get函数 通过mGetter调用invoke函数,间接调用mProperty的get方法,上文已经分析过 Object value = convertBack(mGetter.invoke(target)); ...... } catch (InvocationTargetException e) { ...... } catch (IllegalAccessException e) { ...... } } } } }
void setAnimatedValue(Object target) { if (mProperty != null) { //调用set方法 mProperty.set(target, getAnimatedValue()); } if (mSetter != null) { try { // 如果mProperty 为null,通过mSetter调用invoke函数,间接调用mProperty的set方法,上文已经分析过 mSetter.invoke(target, mTmpValueArray); } catch (InvocationTargetException e) { ...... } catch (IllegalAccessException e) { ...... } } }
a:使用AnimatorSetb:使用PropertyValuesHolderc:使用ViewPropertyAnimator
public Builder with(Animator anim) 将现有动画和传入的动画同时执行 public Builder before(Animator anim) 将现有动画插入到传入的动画之前执行 public Builder after(Animator anim) 将现有动画插入到传入的动画之后执行 public Builder after(long delay) 将现有动画延迟指定毫秒后执行
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_animator_set); container = (LinearLayout) findViewById(R.id.container); img = (ImageView) findViewById(R.id.img); findViewById(R.id.button).setOnClickListener(this); ObjectAnimator animator = ObjectAnimator.ofInt(container, "backgroundColor", 0xFFFF0000, 0xFFFF00FF); ObjectAnimator animator1 = ObjectAnimator.ofFloat(img, "translationX", 0.0f, 200.0f, 0f); ObjectAnimator animator2 = ObjectAnimator.ofFloat(img, "scaleX", 1.0f, 2.0f); ObjectAnimator animator3 = ObjectAnimator.ofFloat(img, "rotationX", 0.0f, 90.0f, 0.0F); ObjectAnimator animator4 = ObjectAnimator.ofFloat(img, "alpha", 1.0f, 0.2f, 1.0F); //组合动画方式1 set = new AnimatorSet(); set.play(animator) .with(animator1) .after(animator2) .after(animator3) .before(animator4); set.setDuration(5000); } @Override public void onClick(View view) { switch (view.getId()) { case R.id.button: set.start(); break; } }
set.playTogether(animator,animator1,animator2,animator3,animator4);
public void playTogether(Animator... items) { if (items != null) { Builder builder = play(items[0]); for (int i = 1; i < items.length; ++i) { builder.with(items[i]); } } }
PropertyValuesHolder valuesHolder = PropertyValuesHolder.ofFloat("translationX", 0.0f, 300.0f); PropertyValuesHolder valuesHolder1 = PropertyValuesHolder.ofFloat("scaleX", 1.0f, 1.5f); PropertyValuesHolder valuesHolder2 = PropertyValuesHolder.ofFloat("rotationX", 0.0f, 90.0f, 0.0F); PropertyValuesHolder valuesHolder3 = PropertyValuesHolder.ofFloat("alpha", 1.0f, 0.3f, 1.0F); objectAnimator = ObjectAnimator.ofPropertyValuesHolder(img, valuesHolder, valuesHolder1, valuesHolder2, valuesHolder3); objectAnimator.setDuration(2000).start();
public static PropertyValuesHolder ofInt(String propertyName, int... values) public static PropertyValuesHolder ofInt(Property, Integer> property, int... values) public static PropertyValuesHolder ofFloat(String propertyName, float... values) public static PropertyValuesHolder ofFloat(Property, Float> property, float... values) public static PropertyValuesHolder ofObject(String propertyName, TypeEvaluator evaluator,Object... values) public static <V> PropertyValuesHolder ofObject(Property property, TypeEvaluator<V> evaluator, V... values) public static PropertyValuesHolder ofKeyframe(String propertyName, Keyframe... values) public static PropertyValuesHolder ofKeyframe(Property property, Keyframe... values)
public abstract ViewPropertyAnimator setDuration(long duration); 设置持续时间 public abstract long getDuration(); 得到持续时间 public abstract long getStartDelay(); 得到开始延迟 public abstract ViewPropertyAnimator setStartDelay(long startDelay); 设置开始延迟 public abstract ViewPropertyAnimator setInterpolator(/*Time*/Interpolator interpolator); 设置插值器 public abstract ViewPropertyAnimator setListener(Animator.AnimatorListener listener); 设置监听器 public abstract void start(); 开始动画 public abstract void cancel(); 取消动画 public abstract ViewPropertyAnimator x(float value); 对属性x执行动画 public abstract ViewPropertyAnimator xBy(float value); 对属性x执行动画 public abstract ViewPropertyAnimator y(float value); 对属性y执行动画 public abstract ViewPropertyAnimator yBy(float value); 对属性y执行动画 public abstract ViewPropertyAnimator rotation(float value); 对属性rotation执行动画 public abstract ViewPropertyAnimator rotationBy(float value); 对属性rotation执行动画 public abstract ViewPropertyAnimator rotationX(float value); 对属性rotationX执行动画 public abstract ViewPropertyAnimator rotationXBy(float value); 对属性rotationX执行动画 public abstract ViewPropertyAnimator rotationY(float value); 对属性rotationY执行动画 public abstract ViewPropertyAnimator rotationYBy(float value); 对属性rotationY执行动画 public abstract ViewPropertyAnimator translationX(float value); 对属性translationX执行动画 public abstract ViewPropertyAnimator translationXBy(float value); 对属性translationX执行动画 public abstract ViewPropertyAnimator translationY(float value); 对属性translationY执行动画 public abstract ViewPropertyAnimator translationYBy(float value); 对属性translationY执行动画 public abstract ViewPropertyAnimator scaleX(float value); 对属性scaleX执行动画 public abstract ViewPropertyAnimator scaleXBy(float value); 对属性scaleX执行动画 public abstract ViewPropertyAnimator scaleY(float value); 对属性scaleY执行动画 public abstract ViewPropertyAnimator scaleYBy(float value); 对属性scaleY执行动画 public abstract ViewPropertyAnimator alpha(float value); 对属性alpha执行动画 public abstract ViewPropertyAnimator alphaBy(float value); 对属性alpha执行动画
public ViewPropertyAnimator animate() { if (mAnimator == null) { mAnimator = new ViewPropertyAnimator(this); } return mAnimator; }
ViewPropertyAnimator viewPropertyAnimator = img.animate(); viewPropertyAnimator.translationX(200).scaleX(2).setDuration(2000).start();
a:给你的对象加上get和set方法,如果你有权限的话
b:用一个类来包装原始对象,间接为其提供get和set方法
c:采用ValueAnimator,监听动画过程,自己实现属性的改变
a:使用AnimatorSet
b:使用PropertyValueHolder
c:使用ViewPropertyAnimator