前言
之前已經講過動畫相關的內容,沒有接觸過的讀者可以看下筆者之前對android動畫使用的整理。
Android動畫總結 (valueAnimator、objectAnimator、AnimatorSet、PropertyValuesHolder、Interpolator)
插值器概念
動畫插值器可以用來控制動畫的變化規律,比如變化速率是先快後慢,還是先慢後快,或者是更細節的其他。
android系統已經提供了一些常用的插值器,基本已經能滿足大部分需求,對此有興趣的可以看下筆者前言中的文章,此處就不徒增篇幅了。
對於具體的業務,有時候系統的插值器也沒法滿足需求。
對於某些場景,一方面需要對動畫速率有較細緻的控制,另一方面可能使用較爲廣泛,需要將此邏輯集成,這時就可以使用自定義的插值器。
例子(Demo)
本文的例子實現了“彈窗彈性效果”的插值器。
主要有三個動畫:
- 使用插值器,從上至下的動畫。
- 使用插值器,從左至右的動畫。
- 不使用插值器,實現與插值器類的效果。(控制上不如插值器細緻)
個人理解:
自定義插值器一般還是要在“對動畫運動規律需要細緻控制”的前提下,大多數情況其實直接像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>