讀前思考
學習一門技術或者看一篇文章最好的方式就是帶著問題去學習,這樣才能在過程中有茅塞頓開、燈火闌珊的感覺,記憶也會更深刻。
- Android中有哪幾種型別的動畫?
- 幀動畫在使用時需要注意什麼?
- View動畫和屬性動畫的區別?
- View動畫為何不能真正改變View的位置?而屬性動畫為何可以?
- 屬性動畫插值器和估值器的作用?
概述
在 Android 開發中,動畫是必不可少的,它可以讓 View 在變化的時候有一個過渡,避免使用者感覺很突兀。因此,學好動畫,用好動畫是非常重要的,會給開發帶來很多快樂。
Android 中動畫分為幀動畫、View 動畫、屬性動畫三種,可以在日常開發中根據需求的不同進行選擇,但基本上現在 90% 以上的都可以用屬性動畫解決,現在讓我們來了解一下三種動畫。
幀動畫
逐幀動畫是一種常見的動畫形式(Frame By Frame),其原理是在“連續的關鍵幀”中分解動畫動作,也就是在時間軸的每幀上逐幀繪製不同的內容,使其連續播放而成動畫。 因為逐幀動畫的幀序列內容不一樣,不但給製作增加了負擔而且最終輸出的檔案量也很大,但它的優勢也很明顯:逐幀動畫具有非常大的靈活性,幾乎可以表現任何想表現的內容,而它類似與電影的播放模式,很適合於表演細膩的動畫。
在 Android 中提供了兩種方式為 AnimationDrawable 新增幀:XML 定義的資原始檔和 Java 程式碼建立。下面我們會逐一進行介紹。
1. 使用 XML 定義的資原始檔設定動畫幀
Android 中的資原始檔放在 /res 目錄下,對於動畫幀的資源需要當成一個 Drawable,所以需要把它放在 /res/Drawable 目錄下。而定義逐幀動畫非常簡單,在 drawable 資料夾下新建 xml 檔案,在 <animation-list.../> 元素中使用 <item.../> 子元素定義動畫的全部幀,並制定各幀的持續時間即可。還可以在 <animation-list.../> 元素中新增屬性,來設定逐幀動畫的屬性。
先上效果圖
XML幀動畫的資原始檔:
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false">
<!-- 定義一個動畫幀,Drawable為img0,持續時間50毫秒 -->
<item android:drawable="@drawable/uncheck_in1" android:duration="200"/>
<item android:drawable="@drawable/uncheck_in2" android:duration="200"/>
<item android:drawable="@drawable/uncheck_in3" android:duration="200"/>
<item android:drawable="@drawable/uncheck_in4" android:duration="200"/>
<item android:drawable="@drawable/uncheck_in5" android:duration="200"/>
<item android:drawable="@drawable/uncheck_in6" android:duration="200"/>
</animation-list>
複製程式碼
Java 程式碼使用動畫
// 通過逐幀動畫的資原始檔獲得AnimationDrawable示例
AnimationDrawable frameAnim = (AnimationDrawable) getResources().getDrawable(R.drawable.part5_frame1);
// 把AnimationDrawable設定為ImageView的背景
mImageView.setBackgroundDrawable(frameAnim);
/**
*根據點選事件控制動畫開啟,停止
*/
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt_start:
frameAnim.start();
break;
case R.id.bt_stop:
frameAnim.stop();
break;
}
}
複製程式碼
2. 使用 Java 程式碼建立逐幀動畫
在 Android 中,除了可以通過 XML 檔案定義一個逐幀動畫之外,還可以通過 AnimationDrawable.addFrame() 方法為 AnimationDrawable 新增動畫幀。
效果圖和上面的一樣,這裡就不放了,直接上程式碼。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_part5_frame_java);
mImageView = findViewById(R.id.iv_frame1);
Button bt_stop = findViewById(R.id.bt_stop);
Button bt_start = findViewById(R.id.bt_start);
bt_start.setOnClickListener(this);
bt_stop.setOnClickListener(this);
frameAnim = new AnimationDrawable();
// 為AnimationDrawable新增動畫幀
frameAnim.addFrame(getResources().getDrawable(R.drawable.uncheck_in1), 200);
frameAnim.addFrame(getResources().getDrawable(R.drawable.uncheck_in2), 200);
frameAnim.addFrame(getResources().getDrawable(R.drawable.uncheck_in3), 200);
frameAnim.addFrame(getResources().getDrawable(R.drawable.uncheck_in4), 200);
frameAnim.addFrame(getResources().getDrawable(R.drawable.uncheck_in5), 200);
frameAnim.addFrame(getResources().getDrawable(R.drawable.uncheck_in6), 200);
frameAnim.setOneShot(false);
mImageView.setBackground(frameAnim);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt_start:
if (frameAnim != null && !frameAnim.isRunning()) {
frameAnim.start();
}
break;
case R.id.bt_stop:
if (frameAnim != null && frameAnim.isRunning()) {
frameAnim.stop();
}
break;
}
}
複製程式碼
使用幀動畫的時候要注意不要使用過大的圖片,會引起 OOM。
View 動畫
View 動畫框架只能用於 Views。 比較容易設定和能滿足許多應用程式的需要。View 動畫框架中一共提供了 AlphaAnimation(透明度動畫)、RotateAnimation(旋轉動畫)、ScaleAnimation(縮放動畫)、TranslateAnimation(平移動畫)四種型別的補間動畫;並且 View 動畫框架還提供了動畫集合類(AnimationSet),通過動畫集合類(AnimationSet)可以將多個補間動畫以組合的形式顯示出來。View 動畫只是顯示效果,View 的實際屬性及位置並未發生變化。
先看效果圖
在 /res 目錄下新建 anim 資料夾,在 anim 資料夾下新建 xml 檔案
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 透明度變化,從 1 到 0-->
<alpha
android:duration="5000"
android:fromAlpha="1.0"
android:toAlpha="0.0"
/>
<!-- 縮放,寬高都是從 1 到 0
pivotX、pivotY 代表縮放中心點的橫豎座標
interpolator 代表動畫模式,我設定為先加速、後減速-->
<scale
android:duration="5000"
android:fromXScale="1.0"
android:fromYScale="1.0"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="0.0"
android:toYScale="0.0"
/>
<!-- 平移動畫,從左上角到右下角-->
<translate
android:duration="5000"
android:fromXDelta="150"
android:fromYDelta="150"
android:toXDelta="200"
android:toYDelta="200"/>
<!-- 旋轉動畫,fromDegrees 初始角度
結束角度 toDegrees-->
<rotate
android:duration="5000"
android:fromDegrees="0"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="+360"/>
</set>
複製程式碼
在程式碼中給 view 新增動畫
ImageView iv_bee=findViewById(R.id.iv_bee);
// 設定動畫資源
Animation loadAnimation =AnimationUtils.loadAnimation(this,R.anim.part5view_anim1);
//動畫結束後保持最後的狀態
loadAnimation.setFillAfter(true);
//給 view 新增動畫
iv_bee.startAnimation(loadAnimation);
複製程式碼
屬性動畫
與屬性動畫相比 View 動畫存在一個缺陷,View 動畫改變的只是 View 的顯示,而沒有改變View的響應區域,並且 View 動畫只能對 View 做四種型別的補間動畫,因此在 Android3.0 及其後續版本中新增了屬性動畫框架。
屬性動畫理論知識有很多講解,可以具體看下面的文章
HenCoder Android 自定義 View 1-6:屬性動畫 Property Animation(上手篇)
我這裡就不講理論了,直接擼效果
1、 數字滾動效果
很簡單的一個數字滾動效果,用屬性動畫也很容易做出來,幾行程式碼搞定
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_part5_object_anim);
mTv_object = findViewById(R.id.tv_object);
Button bt_start=findViewById(R.id.bt_start);
bt_start.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showMoneyAnim(1,500);
}
});
}
private void showMoneyAnim(int mStartValue, int mEndValue) {
ValueAnimator animator = ValueAnimator.ofInt(mStartValue, mEndValue);
animator.setDuration(3000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mTv_object.setText(animation.getAnimatedValue().toString());
}
});
animator.start();
}
複製程式碼
2、 簽到卡片翻轉效果
具體翻轉程式碼,分為上半段和下半段動畫
public class Part4AnimationActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_part4_animation);
final ImageView iv_animation=findViewById(R.id.iv_animation);
iv_animation.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
applyRotation(false,iv_animation,0,-90);
}
});
}
/**
* 設定一個新的三維旋轉的容器檢視。只翻一般,然後設定新的現實內容
*
* @param zheng
* 一個判斷機制 如果為true 則向右翻轉,如果false則向左翻轉
* @param view
* 傳入的片段
* @param start
* 起始位置
* @param end
* 結束位置
*/
public void applyRotation(final boolean zheng, final View view,
final float start, final float end) {
// Find the center of the container
final float centerX = view.getWidth() / 2.0f;
final float centerY = view.getHeight() / 2.0f;
// Create a new 3D rotation with the supplied parameter
// The animation listener is used to trigger the next animation
final Util_Rotate3DAnimation rotation = new Util_Rotate3DAnimation(
start, end, centerX, centerY, 310.0f, true);
rotation.setDuration(500);
rotation.setFillAfter(true);
rotation.setInterpolator(new AccelerateInterpolator());
rotation.setAnimationListener(new DisplayNextView(zheng, view));// 新增監聽執行現實內容的切換
view.startAnimation(rotation);// 執行上半場翻轉動畫
}
/**
* 執行完上半部分旋轉之後,設定要顯示的新的View然後繼續執行下半部分旋轉
*/
private final class DisplayNextView implements Animation.AnimationListener {
private final boolean mPosition;
private final View mView;
private DisplayNextView(boolean zheng, View view) {
mPosition = zheng;
mView = view;
}
public void onAnimationStart(Animation animation) {
}
public void onAnimationEnd(Animation animation) {
mView.post(new SwapViews(mPosition, mView));// 新增新的View
}
public void onAnimationRepeat(Animation animation) {
}
}
/**
* 新增要顯示的新的View,並執行下半部分的旋轉操作
*/
private final class SwapViews implements Runnable {
private final boolean mPosition;
private final ImageView mView;
public SwapViews(boolean position, View view) {
mPosition = position;
mView = (ImageView) view;
}
public void run() {
final float centerX = mView.getWidth() / 2.0f;
final float centerY = mView.getHeight() / 2.0f;
Util_Rotate3DAnimation rotation;
if (mPosition) {
rotation = new Util_Rotate3DAnimation(-90, 0, centerX, centerY,
310.0f, false);
} else {
rotation = new Util_Rotate3DAnimation(90, 0, centerX, centerY,
310.0f, false);
}
mView.setImageResource(R.drawable.head2);
rotation.setDuration(500);
rotation.setFillAfter(true);
rotation.setInterpolator(new DecelerateInterpolator());
mView.startAnimation(rotation);
}
}
}
複製程式碼
文章已經讀到末尾了,不知道最初的幾個問題你都會了嗎?如果不會的話?可以再針對不會的問題進行精讀哦!答案都在文中,相信你肯定可以解決的!