android自定義動畫插值器(Interpolator)

前言

之前已經講過動畫相關的內容,沒有接觸過的讀者可以看下筆者之前對android動畫使用的整理。

Android動畫總結 (valueAnimator、objectAnimator、AnimatorSet、PropertyValuesHolder、Interpolator)

插值器概念

動畫插值器可以用來控制動畫的變化規律,比如變化速率是先快後慢,還是先慢後快,或者是更細節的其他。

android系統已經提供了一些常用的插值器,基本已經能滿足大部分需求,對此有興趣的可以看下筆者前言中的文章,此處就不徒增篇幅了。

對於具體的業務,有時候系統的插值器也沒法滿足需求。
對於某些場景,一方面需要對動畫速率有較細緻的控制,另一方面可能使用較爲廣泛,需要將此邏輯集成,這時就可以使用自定義的插值器。

例子(Demo)

本文的例子實現了“彈窗彈性效果”的插值器。
主要有三個動畫:

  1. 使用插值器,從上至下的動畫。
  2. 使用插值器,從左至右的動畫。
  3. 不使用插值器,實現與插值器類的效果。(控制上不如插值器細緻)

個人理解:
自定義插值器一般還是要在“對動畫運動規律需要細緻控制”的前提下,大多數情況其實直接像Demo中的第三個動畫一樣就可以滿足需求了。

代碼

MainActivity.java

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

  //ui
  private Button btnAnimOne;
  private Button btnAnimTwo;
  private Button btnAnimThree;
  private TextView tvAnim;
  //data
  ObjectAnimator anim;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    initViews();
  }

  private void initViews() {
    tvAnim = findViewById(R.id.tv_anim_main);
    btnAnimOne = findViewById(R.id.btn_anim_one_main);
    btnAnimTwo = findViewById(R.id.btn_anim_two_main);
    btnAnimThree = findViewById(R.id.btn_anim_three_main);

    btnAnimOne.setOnClickListener(this);
    btnAnimTwo.setOnClickListener(this);
    btnAnimThree.setOnClickListener(this);
  }

  private void startAnimOne() {
    if (tvAnim == null || anim != null) {
      return;
    }
    tvAnim.setVisibility(View.INVISIBLE);
    anim = ObjectAnimator.ofFloat(tvAnim, "y", 0, tvAnim.getY());
    anim.setDuration(1000);
    anim.setInterpolator(new ElasticityInterpolator());
    anim.addListener(new AnimatorListenerAdapter() {
      @Override public void onAnimationStart(Animator animation) {
        tvAnim.setVisibility(View.VISIBLE);
      }

      @Override public void onAnimationEnd(Animator animation) {
        anim = null;
      }
    });
    anim.start();
  }

  private void startAnimTwo() {
    if (tvAnim == null || anim != null) {
      return;
    }
    tvAnim.setVisibility(View.INVISIBLE);
    anim = ObjectAnimator.ofFloat(tvAnim, "x", 0, tvAnim.getX());
    anim.setDuration(1000);
    anim.setInterpolator(new ElasticityInterpolator());
    anim.addListener(new AnimatorListenerAdapter() {
      @Override public void onAnimationStart(Animator animation) {
        tvAnim.setVisibility(View.VISIBLE);
      }

      @Override public void onAnimationEnd(Animator animation) {
        anim = null;
      }
    });
    anim.start();
  }

  private void startAnimThree() {
    if (tvAnim == null || anim != null) {
      return;
    }
    tvAnim.setVisibility(View.INVISIBLE);
    float x = tvAnim.getX();
    anim = ObjectAnimator.ofFloat(tvAnim, "x", 0, x * 1.2f, x * 0.9f, x * 1.1f, x * 0.9f, x);
    anim.setDuration(1000);
    anim.addListener(new AnimatorListenerAdapter() {
      @Override public void onAnimationStart(Animator animation) {
        tvAnim.setVisibility(View.VISIBLE);
      }

      @Override public void onAnimationEnd(Animator animation) {
        anim = null;
      }
    });
    anim.start();
  }

  @Override public void onClick(View v) {
    int id = v.getId();
    switch (id) {
      case R.id.btn_anim_one_main:
        startAnimOne();
        break;
      case R.id.btn_anim_two_main:
        startAnimTwo();
        break;
      case R.id.btn_anim_three_main:
        startAnimThree();
        break;
    }
  }
}

ElasticityInterpolator.java

public class ElasticityInterpolator extends BaseInterpolator {

  /**
   * @param input 表示動畫進度,大小從0到1
   */
  @Override public float getInterpolation(float input) {

    if (input <= 0.5) {
      return input * 2;
    } else if (input <= 0.6f) {
      return 1 + (input - 0.5f) * 2;
    } else if (input <= 0.7) {
      return 1.2f - ((input - 0.6f) * 3);
    } else if (input <= 0.8) {
      return 0.9f + ((input - 0.7f) * 2);
    } else if (input <= 0.9) {
      return 1.1f - ((input - 0.8f) * 2);
    } else if (input <= 1) {
      return input;
    }
    return 0;
  }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    tools:context=".MainActivity"
    >
  <TextView
      android:id="@+id/tv_anim_main"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="提示"
      android:textSize="30sp"
      android:textStyle="bold"
      android:elevation="100dp"
      />
  <Button
      android:id="@+id/btn_anim_one_main"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="豎向動畫"
      android:textSize="30sp"
      />
  <Button
      android:id="@+id/btn_anim_two_main"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="橫向動畫"
      android:textSize="30sp"
      />
  <Button
      android:id="@+id/btn_anim_three_main"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="非插值器實現"
      android:textSize="30sp"
      />

</LinearLayout>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章