摘要:又和大家见面了,这几天一直在忙大创项目,所以没有更新博客,而且我发现看源码这个东西必须写个博客或者笔记啊,这之前一段时机笔者已经看了ValueAnimator和ObjectAnimator的源码了,但是这才过了几天,搞了会别的事情就忘得几乎一干二净了。现在又要重头看一遍很痛苦额-。+。

脚本宝典收集整理的这篇文章主要介绍了

ObjectAnimator属性动画源码分析篇

脚本宝典小编觉得挺不错的,现在分享给大家,也给大家做个参考,希望能帮助你少写一行代码,多一份安全和惬意。

又和大家见面了,这几天一直在忙大创项目,所以没有更新博客,而且我发现看源码这个东西必须写个博客或者笔记啊,这之前一段时机笔者已经看了ValueAnimator和ObjectAnimator的源码了,但是这才过了几天,搞了会别的事情就忘得几乎一干二净了。现在又要重头看一遍很痛苦额-。+。

另外,笔者已经在简书写了关于属性动画的比较系统的详细的文章,之后会陆续在CSDN上重新写的(是重新写,不是复制过去哦,因为第一次写的实在是太烂了-。=)

好了不继续扯皮了,我们看来一下今天想要讲的东西――ObjectAnimator的源码分析(使用部分)。

ObjectAnimator使用部分源码

我们都知道属性动画使用分为三部分:创建、添加属性、启动。而我们今天要讲的就是关于创建和添加属性。首先来看创建的源码吧:

创建

首先看一下今天所有用到的背景:

写了一个自定义的View――PointView,用来实现一个小球的移动效果,PointView代码如下(可以不用看-。+):

 public class PointView extends View {   private Point mCurrentPoint;   private Paint paint;   /**    * 两个构造方法    **/   public PointView(Context context) {     super(context);     paint = new Paint(Paint.ANTI_ALIAS_FLAG);     paint.setColor(Color.CYAN);     paint.setStrokeWidth(5);     paint.setStyle(Paint.Style.STROKE);   }   public PointView(Context context, @Nullable AttributeSet attrs) {     super(context, attrs);     paint = new Paint(Paint.ANTI_ALIAS_FLAG);     paint.setColor(Color.CYAN);     paint.setStrokeWidth(5);     paint.setStyle(Paint.Style.STROKE);   }   /**    * onDraw开始使用画笔,如果mCurrentPoint为空,就创建Point对象,    * 否则就直接调用drawPoint方法    **/   @Override   protected void onDraw(Canvas canvas) {     super.onDraw(canvas);     if (mCurrentPoint == null) {       mCurrentPoint = new Point(500, 500);       drawPoint(canvas);     } else {       drawPoint(canvas);     }   }   //设置一个属性添加的方法   public void setMove(Point point) {     mCurrentPoint = point;     invalidate();   }   //启动动画   private void startAnimation() {     ObjectAnimator animator = ObjectAnimator.ofObject(PointView.this, "Move", new BallEvaluator(),         new Point(500, 500),         new Point(500, 800), new Point(700, 800));     animator.setInterpolator(new LinearInterpolator());     animator.setDuration(5000);     animator.start();   }   //在外部调用的方法,通过此方法,开启小球动作的动画。   public void moveBall() {     startAnimation();   }   private void drawPoint(Canvas canvas) {     canvas.drawCircle(mCurrentPoint.getX(), mCurrentPoint.getY(), 30, paint);   }   //小球对象的估值器   public class BallEvaluator implements TypeEvaluator {     float x;     float y;     @Override     public Point evaluate(float fraction, Point startValue, Point endValue) {       float startX = startValue.getX();       float startY = startValue.getY();       float endX = endValue.getX();       float endY = endValue.getY();       x = fraction * (endX - startX);       y = fraction * (endY - startY);       Log.e("ASDSAD", "x = " + x + "y = " + y);       return new Point(startX + x, startY + y);     }   } }

代码可能有点多,不过这不是主要的,我们今天关注的只是属性动画,所以我们只需要看里面的startAnimation方法和setMove方法就好:

  • setMove:由于我们知道属性动画ObjectAnimator类是通过将propertyName拼接成对应的set方法,然后通过反射机制去调用该方法,所以我们需要有一个对应的set方法。
  • startAnimation:这个方法我们用来设置我们的动画以及启动动画。setMove方法,很简单,我们只是将传入的新的小球对象赋值给了mCurrentBall,然后调用invalidate方法重新绘制。下面看一下startAnimation方法:
 ObjectAnimator animator = ObjectAnimator.ofObject(PointView.this, "Move", new BallEvaluator(),         new Point(500, 500),         new Point(500, 800), new Point(700, 800));     animator.setInterpolator(new LinearInterpolator());     animator.setDuration(5000);     animator.start();

我们看一下先进入ofObject方法(相信ofObject里面的参数大家都看得懂):

 public static ObjectAnimator ofObject(Object target, String propertyName,       TypeEvaluator evaluator, Object... values) {     ObjectAnimator anim = new ObjectAnimator(target, propertyName);     anim.setObjectValues(values);     anim.setEvaluator(evaluator);     return anim;   }

我们发现ofObject是一个静态方法:他在里面创建了一个ObjectAnimator对象。然后调用了setObjeectValues和setEvaluator方法,分别添加了数据和估值器。

也就是这个ofObject里面有三个入口等着我们进去:

  • ObjectAnimator的构造方法
  • setObjectValues方法
  • setEvaluator方法

那我们先从ObjectAnimator的构造方法开始看吧。

ObjectAnimator构造方法:

   private ObjectAnimator(Object target, String propertyName) {     setTarget(target);     setPropertyName(propertyName);   }

又是两个方法,一个一个去看,先进入setTarget:

   @Override   public void setTarget(@Nullable Object target) {     final Object oldTarget = getTarget();     if (oldTarget != target) {       if (isStarted()) {         cancel();       }       mTarget = target == null ? null : new WeakReference(target);       // New target should cause re-initialization prior to starting       mInitialized = false;     }   }

这些代码都能够知道什么意思,这个方法我们只需要注意两点:

  • 我们将传入的target传给了mTarget这个弱引用。
  • mInitialized = false;这个属性我们可以这么理解,在他的ObjectAnimator没有准备就绪(初始化过程尚未完成时),他一直都是false。

这个方法跳过。

然后我们看setPropertyName方法:

   public void setPropertyName(@NonNull String propertyName) {     // mValues could be null if this is being constructed piecemeal. Just record the     // propertyName to be used later when setValues() is called if so.     if (mValues != null) {       PropertyValuesHolder valuesHolder = mValues[0];       String oldName = valuesHolder.getPropertyName();       valuesHolder.setPropertyName(propertyName);       mValuesMap.remove(oldName);       mValuesMap.put(propertyName, valuesHolder);     }     mPropertyName = propertyName;     // New property/values/target should cause re-initialization prior to starting     mInitialized = false;   }

首先介绍一下mValues和mValuesMap这两个属性,他们都是存储PropertyValueHolder的属性,而且储存的都一样,只是mValuesMap可以让我们通过propertyName来查找对应的PropertyValueHolder。

 PropertyValuesHolder[] mValues; HashMap mValuesMap;

这个方法只是将propertyName放入PropertyValueHolder中(具体逻辑如上,先判断mValues是否为空,如果不为空就将propertyName放入mValues和mValuesMap中,最后将propertyName赋值给mPropertyName),可以过了。

现在我们的ObjectAnimator构造方法看完了,我们接着看setObjectValues方法:

anim.setObjectValues:

   @Override   public void setObjectValues(Object... 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) {         setValues(PropertyValuesHolder.ofObject(mProperty, (TypeEvaluator) null, values));       } else {         setValues(PropertyValuesHolder.ofObject(mPropertyName,             (TypeEvaluator) null, values));       }     } else {       super.setObjectValues(values);     }   }

这段代码的总体逻辑只有一个:如果mValues没有值,那么就调用setValues方法,否则就调用父类的setObjectValues方法。

感觉很乱啊,稳住! ? 我们这是第一次创建的对象,所以肯定是为空的,所以我们只需要看setValues方法就好了,但是注意,这里还有PropertyValueHolder,所以我们决定先看一下PropertyValueHolder的ofObject方法:

PropertyValueHolder.ofObject:

   public static  PropertyValuesHolder ofObject(Property property,       TypeEvaluator evaluator, V... values) {     PropertyValuesHolder pvh = new PropertyValuesHolder(property);     pvh.setObjectValues(values);     pvh.setEvaluator(evaluator);     return pvh;   }

跟上面ObjectAnimator的ofObject差异不多,我们就不多说了,有两条路可以选:

  • setObjectValues
  • setEvaluator

先看setObjectValues:

PropertyValueHolder.setObjectValues:

   public void setObjectValues(Object... values) {     mValueType = values[0].getClass();     mKeyframes = KeyframeSet.ofObject(values);     if (mEvaluator != null) {       mKeyframes.setEvaluator(mEvaluator);     }   }

我知道大家都快吐了,现在KeyFrames又出来了,头皮发麻对吧,稳住,我们坚持住!

这个KeyFrames是KeyFrameSet的接口,我们看一下KeyframeSet的ofObject方法:

KeyframeSet.ofObject方法:

   public static KeyframeSet ofObject(Object... values) {     int numKeyframes = values.length;     ObjectKeyframe keyframes[] = new ObjectKeyframe[Math.max(numKeyframes,2)];//创建了一个至少为两位的ObjectKeyFrame对象     if (numKeyframes == 1) {       keyframes[0] = (ObjectKeyframe) Keyframe.ofObject(0f);       keyframes[1] = (ObjectKeyframe) Keyframe.ofObject(1f, values[0]);     } else {       keyframes[0] = (ObjectKeyframe) Keyframe.ofObject(0f, values[0]);       for (int i = 1; i < numKeyframes; ++i) {         keyframes[i] = (ObjectKeyframe) Keyframe.ofObject((float) i / (numKeyframes - 1), values[i]);       }     }     return new KeyframeSet(keyframes);   }

我们终于看到了一个比较熟悉的类,KeyFrame,这个叫做关键帧的类终于出现了,我们简单分析一下这个方法:

首先创建了一个至少为两位的ObjectKeyFrame对象,然后对values的长度进行判断,如果只有一个值,那么就将唯一的一个值添加到最后一位(此时也就是第二位),否则就依次添加。最后将ObjectKeyFrame的数组转换成KeyFrameSet类型返回。

现在我们回到PropertyValueHolder的setObjectValues方法中,接下来我们要看一下setEvaluator方法(需要在KeyFrameSet中查看)

KeyFrameSet.setEvaluator方法:

   public void setEvaluator(TypeEvaluator evaluator) {     mEvaluator = evaluator;   }

这个不用多说,直接过。

现在我们的PropertyValueHolder的ofObject方法已经看完了,我们跳回anim.setObjectValues方法,看一下setValues方法:

setValues:

   public void setValues(PropertyValuesHolder... values) {     int numValues = values.length;     mValues = values;     mValuesMap = new HashMap(numValues);     for (int i = 0; i < numValues; ++i) {       PropertyValuesHolder valuesHolder = values[i];       mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder);     }     // New property/values/target should cause re-initialization prior to starting     mInitialized = false;   }

这个完全就是我们刚才说的储存PropertyValueHolder的两个属性mValues和mValuesMap添加数据的过程,过。

现在我们只差最后一个大方法了,anim.setEvaluator了,激动!!!

anim.setEvaluator方法:

   public void setEvaluator(TypeEvaluator value) {     if (value != null && mValues != null && mValues.length > 0) {       mValues[0].setEvaluator(value);     }   }

这个方法是给每个PropertyValueHolder对象都执行setEvaluator方法,我们点进去这个方法看一下:

PropertyValueHolder.setEvaluator方法:

   public void setEvaluator(TypeEvaluator evaluator) {     mEvaluator = evaluator;     mKeyframes.setEvaluator(evaluator);   }

又进入了Keyframes的setEvaluator,我们接着看一下KeyFrameSet的setEvaluator方法:

KeyFrameSet.setEvaluator方法:

   public void setEvaluator(TypeEvaluator evaluator) {     mEvaluator = evaluator;   }

这个方法不用说了。

最后我们返回了创建的anim的对象,到现在为止,我们得到我们想要的ObjectAnimator对象了。

这个过程是有点繁琐,我们现在屡一下思路:

调用了ObjectAnimator.ofObject之后

  1. 首先new一个ObjectAnimator对象,进入ObjectAnimator的构造方法中:在构造方法中,我们执行了两个方法:setTarget和setPropertyName。
  2. 然后调用了ObjectAnimator的setObjectValues方法:在这个方法中我们首先实例化了PropertyValueHolder对象,然后调用setValues方法将PropertyValueHolder传入。
  3. 之后调用了ObjectAnimator的setEvaluator方法:添加了估值器。
  4. 最后返回了ObjectAnimator对象。

到这里我们就完成了ObjectAnimator对象实例的创建。

到这里创建部分就全部完成了,接下来我们看一下添加属性,这个就很简单了。

添加属性

我们就举一个方法为例吧,拿setInterpolator方法为例:

   public void setInterpolator(TimeInterpolator value) {     if (value != null) {       mInterpolator = value;     } else {       mInterpolator = new LinearInterpolator();     }   }

这个方法是我们添加插值器的方法,我们注意到他只是给mInterpolator赋值而已,如果传入为空,则添加线性插值器。

其他的添加属性的方法,像setDuration、setRepeatCount等都是如此,大家下去就自己看一下吧。

由于还不会用 starUML,所以现在还没发画一张时序图(只是手画的,估计大家也不想看哈哈),等学完UML之后会给大家补上的,希望这篇文章大家喜欢。

ObjectAnimator属性动画源码分析篇-脚本宝典

总结

android教程
脚本网站
android studio

总结

以上是脚本宝典为你收集整理的

ObjectAnimator属性动画源码分析篇

全部内容,希望文章能够帮你解决

ObjectAnimator属性动画源码分析篇

所遇到的程序开发问题,欢迎加入QQ群277859234一起讨论学习。如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典网站推荐给程序员好友。 本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。

80%的人都看过