欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

ObjectAnimator屬性動(dòng)畫源碼分析篇

 更新時(shí)間:2019年01月14日 16:31:31   作者:Zy_JiBai  
今天小編就為大家分享一篇關(guān)于ObjectAnimator屬性動(dòng)畫源碼分析篇,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧

又和大家見面了,這幾天一直在忙大創(chuàng)項(xiàng)目,所以沒有更新博客,而且我發(fā)現(xiàn)看源碼這個(gè)東西必須寫個(gè)博客或者筆記啊,這之前一段時(shí)機(jī)筆者已經(jīng)看了ValueAnimator和ObjectAnimator的源碼了,但是這才過了幾天,搞了會(huì)別的事情就忘得幾乎一干二凈了?,F(xiàn)在又要重頭看一遍很痛苦額-。+。

另外,筆者已經(jīng)在簡書寫了關(guān)于屬性動(dòng)畫的比較系統(tǒng)的詳細(xì)的文章,之后會(huì)陸續(xù)在CSDN上重新寫的(是重新寫,不是復(fù)制過去哦,因?yàn)榈谝淮螌懙膶?shí)在是太爛了-。=)

好了不繼續(xù)扯皮了,我們看來一下今天想要講的東西——ObjectAnimator的源碼分析(使用部分)。

ObjectAnimator使用部分源碼

我們都知道屬性動(dòng)畫使用分為三部分:創(chuàng)建、添加屬性、啟動(dòng)。而我們今天要講的就是關(guān)于創(chuàng)建和添加屬性。首先來看創(chuàng)建的源碼吧:

創(chuàng)建

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

寫了一個(gè)自定義的View——PointView,用來實(shí)現(xiàn)一個(gè)小球的移動(dòng)效果,PointView代碼如下(可以不用看-。+):

public class PointView extends View {
  private Point mCurrentPoint;
  private Paint paint;
  /**
   * 兩個(gè)構(gòu)造方法
   **/
  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為空,就創(chuàng)建Point對(duì)象,
   * 否則就直接調(diào)用drawPoint方法
   **/
  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if (mCurrentPoint == null) {
      mCurrentPoint = new Point(500, 500);
      drawPoint(canvas);
    } else {
      drawPoint(canvas);
    }
  }
  //設(shè)置一個(gè)屬性添加的方法
  public void setMove(Point point) {
    mCurrentPoint = point;
    invalidate();
  }
  //啟動(dòng)動(dòng)畫
  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();
  }
  //在外部調(diào)用的方法,通過此方法,開啟小球動(dòng)作的動(dòng)畫。
  public void moveBall() {
    startAnimation();
  }
  private void drawPoint(Canvas canvas) {
    canvas.drawCircle(mCurrentPoint.getX(), mCurrentPoint.getY(), 30, paint);
  }
  //小球?qū)ο蟮墓乐灯?
  public class BallEvaluator implements TypeEvaluator<Point> {
    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);
    }
  }
}

代碼可能有點(diǎn)多,不過這不是主要的,我們今天關(guān)注的只是屬性動(dòng)畫,所以我們只需要看里面的startAnimation方法和setMove方法就好:

  • setMove:由于我們知道屬性動(dòng)畫ObjectAnimator類是通過將propertyName拼接成對(duì)應(yīng)的set方法,然后通過反射機(jī)制去調(diào)用該方法,所以我們需要有一個(gè)對(duì)應(yīng)的set方法。
  • startAnimation:這個(gè)方法我們用來設(shè)置我們的動(dòng)畫以及啟動(dòng)動(dòng)畫。setMove方法,很簡單,我們只是將傳入的新的小球?qū)ο筚x值給了mCurrentBall,然后調(diào)用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();

我們看一下先進(jìn)入ofObject方法(相信ofObject里面的參數(shù)大家都看得懂):

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;
  }

我們發(fā)現(xiàn)ofObject是一個(gè)靜態(tài)方法:他在里面創(chuàng)建了一個(gè)ObjectAnimator對(duì)象。然后調(diào)用了setObjeectValues和setEvaluator方法,分別添加了數(shù)據(jù)和估值器。

也就是這個(gè)ofObject里面有三個(gè)入口等著我們進(jìn)去:

  • ObjectAnimator的構(gòu)造方法
  • setObjectValues方法
  • setEvaluator方法

那我們先從ObjectAnimator的構(gòu)造方法開始看吧。

ObjectAnimator構(gòu)造方法:

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

又是兩個(gè)方法,一個(gè)一個(gè)去看,先進(jìn)入setTarget:

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

這些代碼都能夠知道什么意思,這個(gè)方法我們只需要注意兩點(diǎn):

  • 我們將傳入的target傳給了mTarget這個(gè)弱引用。
  • mInitialized = false;這個(gè)屬性我們可以這么理解,在他的ObjectAnimator沒有準(zhǔn)備就緒(初始化過程尚未完成時(shí)),他一直都是false。

這個(gè)方法跳過。

然后我們看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這兩個(gè)屬性,他們都是存儲(chǔ)PropertyValueHolder的屬性,而且儲(chǔ)存的都一樣,只是mValuesMap可以讓我們通過propertyName來查找對(duì)應(yīng)的PropertyValueHolder。

PropertyValuesHolder[] mValues;
HashMap<String, PropertyValuesHolder> mValuesMap;

這個(gè)方法只是將propertyName放入PropertyValueHolder中(具體邏輯如上,先判斷mValues是否為空,如果不為空就將propertyName放入mValues和mValuesMap中,最后將propertyName賦值給mPropertyName),可以過了。

現(xiàn)在我們的ObjectAnimator構(gòu)造方法看完了,我們接著看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);
    }
  }

這段代碼的總體邏輯只有一個(gè):如果mValues沒有值,那么就調(diào)用setValues方法,否則就調(diào)用父類的setObjectValues方法。

感覺很亂啊,穩(wěn)??!   我們這是第一次創(chuàng)建的對(duì)象,所以肯定是為空的,所以我們只需要看setValues方法就好了,但是注意,這里還有PropertyValueHolder,所以我們決定先看一下PropertyValueHolder的ofObject方法:

PropertyValueHolder.ofObject:

  public static <V> PropertyValuesHolder ofObject(Property property,
      TypeEvaluator<V> 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);
    }
  }

我知道大家都快吐了,現(xiàn)在KeyFrames又出來了,頭皮發(fā)麻對(duì)吧,穩(wěn)住,我們堅(jiān)持??!

這個(gè)KeyFrames是KeyFrameSet的接口,我們看一下KeyframeSet的ofObject方法:

KeyframeSet.ofObject方法:

  public static KeyframeSet ofObject(Object... values) {
    int numKeyframes = values.length;
    ObjectKeyframe keyframes[] = new ObjectKeyframe[Math.max(numKeyframes,2)];//創(chuàng)建了一個(gè)至少為兩位的ObjectKeyFrame對(duì)象
    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);
  }

我們終于看到了一個(gè)比較熟悉的類,KeyFrame,這個(gè)叫做關(guān)鍵幀的類終于出現(xiàn)了,我們簡單分析一下這個(gè)方法:

首先創(chuàng)建了一個(gè)至少為兩位的ObjectKeyFrame對(duì)象,然后對(duì)values的長度進(jìn)行判斷,如果只有一個(gè)值,那么就將唯一的一個(gè)值添加到最后一位(此時(shí)也就是第二位),否則就依次添加。最后將ObjectKeyFrame的數(shù)組轉(zhuǎn)換成KeyFrameSet類型返回。

現(xiàn)在我們回到PropertyValueHolder的setObjectValues方法中,接下來我們要看一下setEvaluator方法(需要在KeyFrameSet中查看)

KeyFrameSet.setEvaluator方法:

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

這個(gè)不用多說,直接過。

現(xiàn)在我們的PropertyValueHolder的ofObject方法已經(jīng)看完了,我們跳回anim.setObjectValues方法,看一下setValues方法:

setValues:

  public void setValues(PropertyValuesHolder... values) {
    int numValues = values.length;
    mValues = values;
    mValuesMap = new HashMap<String, PropertyValuesHolder>(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;
  }

這個(gè)完全就是我們剛才說的儲(chǔ)存PropertyValueHolder的兩個(gè)屬性mValues和mValuesMap添加數(shù)據(jù)的過程,過。

現(xiàn)在我們只差最后一個(gè)大方法了,anim.setEvaluator了,激動(dòng)?。?!

anim.setEvaluator方法:

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

這個(gè)方法是給每個(gè)PropertyValueHolder對(duì)象都執(zhí)行setEvaluator方法,我們點(diǎn)進(jìn)去這個(gè)方法看一下:

PropertyValueHolder.setEvaluator方法:

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

又進(jìn)入了Keyframes的setEvaluator,我們接著看一下KeyFrameSet的setEvaluator方法:

KeyFrameSet.setEvaluator方法:

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

這個(gè)方法不用說了。

最后我們返回了創(chuàng)建的anim的對(duì)象,到現(xiàn)在為止,我們得到我們想要的ObjectAnimator對(duì)象了。

這個(gè)過程是有點(diǎn)繁瑣,我們現(xiàn)在屢一下思路:

調(diào)用了ObjectAnimator.ofObject之后

  1. 首先new一個(gè)ObjectAnimator對(duì)象,進(jìn)入ObjectAnimator的構(gòu)造方法中:在構(gòu)造方法中,我們執(zhí)行了兩個(gè)方法:setTarget和setPropertyName。
  2. 然后調(diào)用了ObjectAnimator的setObjectValues方法:在這個(gè)方法中我們首先實(shí)例化了PropertyValueHolder對(duì)象,然后調(diào)用setValues方法將PropertyValueHolder傳入。
  3. 之后調(diào)用了ObjectAnimator的setEvaluator方法:添加了估值器。
  4. 最后返回了ObjectAnimator對(duì)象。

到這里我們就完成了ObjectAnimator對(duì)象實(shí)例的創(chuàng)建。

到這里創(chuàng)建部分就全部完成了,接下來我們看一下添加屬性,這個(gè)就很簡單了。

添加屬性

我們就舉一個(gè)方法為例吧,拿setInterpolator方法為例:

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

這個(gè)方法是我們添加插值器的方法,我們注意到他只是給mInterpolator賦值而已,如果傳入為空,則添加線性插值器。

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

由于還不會(huì)用 starUML,所以現(xiàn)在還沒發(fā)畫一張時(shí)序圖(只是手畫的,估計(jì)大家也不想看哈哈),等學(xué)完UML之后會(huì)給大家補(bǔ)上的,希望這篇文章大家喜歡。

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請(qǐng)查看下面相關(guān)鏈接

相關(guān)文章

最新評(píng)論