前言
最適合的才是最好的,這里和大家分享下動畫使用中的一些細節,還有一兩個例子來綜合一下,其實這個內容是很基礎的,原諒筆者實在沒空,沒有為了本文去單獨寫一個demo,更沒有做GIF來演示,本文僅是作為備忘,有不準確的地方,歡迎大家指出,筆者及時改正,共同學習。
Part1
ObjectAnimator動畫是常常會被初學者忽視的一類動畫,估計和當下太多的貝塞爾曲線有關,筆者剛剛進入團隊的時候發現,很多絢麗的動畫其實并沒有用到很高級的東西,團隊的程序員老鳥表示ObjectAnimator就夠了,而且效果蠻好。
1、基礎
大多數動畫由透明度動畫(alpha)、平移動畫(translate)、縮放動畫(scale)、旋轉動畫(rotate)組成,這四個在開發中最常使用,其實也是夠用了,很多復雜的動畫可以拆分為簡單的動畫加以實現,用幾句代碼即可完成:
ObjectAnimator view_ani = ObjectAnimator.ofFloat(view, "alpha", 0, 1);
第一個參數是需要進行動畫操作的對象,比如一個ImageView
第二個參數是動畫的類別,這里進行透明度變化操作,所以是"alpha"
第三、第四個是動畫操作的范圍,這里指透明度為0到透明度100%
其他的動畫大多這個格式
ObjectAnimator logo_zoom_ani = ObjectAnimator.ofFloat(logoZoom, "translationY", -ScreenUtil.dip2px(this, 140));
ObjectAnimator bgView_ani1 = ObjectAnimator.ofFloat(bgView, "scaleX", 1.0f, 1.5f);
ObjectAnimator bgView_ani2 = ObjectAnimator.ofFloat(bgView, "scaleY", 1.0f, 1.5f);
上面有幾個需要注意的地方,第一是平移和縮放是有方向的,所以在代碼中要指定translationX、translationY還有scaleX、scaleY。其次就是對于平移動畫,要想到適配的問題,筆者用工具類把px轉dp。
2、一個例子
寫一個綜合的例子吧,比如要完成一個背景縮放且透明度漸變,與此同時,Logo在上滑的動畫,那么下面的代碼或許對你有幫助:
DecelerateInterpolator decelerateInterpolator = new DecelerateInterpolator();
AnimatorSet set = new AnimatorSet();
// 背景縮放動畫
ObjectAnimator bgView_ani0 = ObjectAnimator.ofFloat(bgView, "alpha", 0, 1);
ObjectAnimator bgView_ani1 = ObjectAnimator.ofFloat(bgView, "scaleX", 1.0f, 1.5f);
ObjectAnimator bgView_ani2 = ObjectAnimator.ofFloat(bgView, "scaleY", 1.0f, 1.5f);
// logo、slogan區域動畫
ObjectAnimator logo_zoom_ani = ObjectAnimator.ofFloat(logoZoom, "translationY", -ScreenUtil.dip2px(this, 140));
bgView_ani0.setInterpolator(decelerateInterpolator);
bgView_ani1.setInterpolator(decelerateInterpolator);
bgView_ani2.setInterpolator(decelerateInterpolator);
logo_zoom_ani.setInterpolator(decelerateInterpolator);
bgView_ani0.setDuration(1500);
bgView_ani1.setDuration(12000);
bgView_ani2.setDuration(12000);
logo_zoom_ani.setDuration(1000).setStartDelay(1500);
set.playTogether(bgView_ani0, bgView_ani1, bgView_ani2,logo_zoom_ani);
set.start();
Part2
1、基礎
這里先說說AnimatorSet AnimationSet 的區別,AnimatorSet 和 AnimationSet 都是動畫集合,Animation 是針對視圖外觀的動畫實現,動畫被應用時外觀改變但視圖的觸發點不會發生變化,還是在原來定義的位置。Animator 是針對視圖屬性的動畫實現,動畫被應用時對象屬性產生變化,最終導致視圖外觀變化。
2、一個例子
AnimatorSet的內容大概就是上面那么多,下面用一個心跳動畫來闡述AnimationSet,先上代碼:
private void playHeartbeatAnimation() {
AnimationSet swellAnimationSet = new AnimationSet(true);
swellAnimationSet.addAnimation(new ScaleAnimation(1.0f, 1.13f, 1.0f, 1.13f, Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f));
swellAnimationSet.addAnimation(new AlphaAnimation(1.0f, 0.3f));
swellAnimationSet.setDuration(1000);
swellAnimationSet.setInterpolator(new AccelerateInterpolator());
swellAnimationSet.setFillAfter(true);
swellAnimationSet.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
AnimationSet shrinkAnimationSet = new AnimationSet(true);
shrinkAnimationSet.addAnimation(new ScaleAnimation(1.13f, 1.0f, 1.13f, 1.0f, Animation.RELATIVE_TO_SELF,
0.5f, Animation.RELATIVE_TO_SELF, 0.5f));
shrinkAnimationSet.addAnimation(new AlphaAnimation(0.3f, 1.0f));
shrinkAnimationSet.setDuration(2000);
shrinkAnimationSet.setInterpolator(new DecelerateInterpolator());
shrinkAnimationSet.setFillAfter(false);
goBtn.startAnimation(shrinkAnimationSet);// 動畫結束時重新開始,實現心跳的View
}
});
goBtn.startAnimation(swellAnimationSet);
}
代碼結構其實蠻簡單的,無非是一個放大動畫加一個縮小動畫,使用差值器修改下運行速度,大致的雛形就出來了,拿AlphaAnimation來說,參數和ObjectAnimator沒什么差別,大家可以試試看,效果其實還是可以的。
3、對例子的優化
很多項目中會開啟一個線程來操作一些循環的東西,那么同樣我們可以利用線程實現心跳動畫的持續。
private class HeatbeatThread extends Thread {
int anInt = 0;
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
public void run() {
//if (anInt < 2) {
playHeartbeatAnimation();
// anInt++;
//}
}
});
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
;
}
有時候我們需要手動去開啟和停止心跳,比如finish掉activity之前需要停止所有的動畫,否則就有可能造成內存泄漏等等,這里附上開啟和停止動畫的代碼:
/**
* 開始心跳
*/
private void startHeartBeat() {
if (heartbeatThread == null) {
heartbeatThread = new HeatbeatThread();
}
if (!heartbeatThread.isAlive()) {
heartbeatThread.start();
}
}
/**
* 停止心跳
*/
private void stopHeartBeat() {
if (heartbeatThread != null && heartbeatThread.isInterrupted()) {
heartbeatThread.interrupt();
heartbeatThread = null;
System.gc();
}
}