我們知道在Android動畫裏,子類的動畫很難飛出父類的範圍,然而項目中又會經常需要各種大範圍動畫特效,比如購物車特效,拖拽特效等等,攻城獅們給出的解決方案也是多種多樣,今天我給大家帶來的就是一種常見的方法,即在Activity的頂層添加一層RelativeLayout佈局,此佈局專用於執行動畫特效,結合動畫工廠類AnimalHelper,可以很方便的實現我們想要的全局動畫特效,由於其位於佈局的最頂層,且全局隨用隨到,於是我把這種方式形象的定義爲"動畫空中支援方式".
代碼如下:
1, MainActivity.java
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
final ImageView srcIv = (ImageView)findViewById(R.id.srcImageView);
final ImageView targetIv = (ImageView)findViewById(R.id.targetImageView);
srcIv.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (!AnimationHelper.isFlyAnimationWorking) {
AnimationHelper.flyAnimation(MainActivity.this, srcIv, targetIv);
}
}
});
}
public RelativeLayout getAnimationLayout() {
return (RelativeLayout)findViewById(R.id.animation_layout);
}
}
我們給srcIv設置監聽,點擊後執行購物車動畫,飛向targetIv,在監聽裏判斷是否在滑動狀態,已保持飛行過程中不響應點擊事件
2, activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#AAAAAA"
android:orientation="vertical">
<ImageView
android:id="@+id/targetImageView"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_margin="10dp"
android:layout_gravity="right"
android:background="#FF0000"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/srcImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/child"
android:background="#00FF00"/>
</LinearLayout>
</LinearLayout>
<RelativeLayout
android:id="@+id/animation_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
主佈局裏主要是2層,從下往上第一層是模擬標題欄佈局,第二層就是我們的動畫層.
3, AnimationHelper.java
public class AnimationHelper {
/*用於記錄是否有購物車動畫在運行*/
public static boolean isFlyAnimationWorking = false;
/*
* activity:傳入的帶有動畫層的Activity
* srcView:購物車動畫的起點View
* targetView:購物車動畫的終點View
*/
public static void flyAnimation(Activity activity, View srcView, final View targetView) {
flyAnimation(activity, srcView, targetView, getBitmapFromView(srcView));
}
/*
* activity:傳入的帶有動畫層的Activity
* srcView:購物車動畫的起點View
* targetView:購物車動畫的終點View
* animationBitmap:顯示在動畫層上的位圖數據
*/
public static void flyAnimation(Activity activity, View srcView, final View targetView, Bitmap animationBitmap) {
if (srcView == null || targetView == null) {
return;
}
int[] srcXY = new int[2];
srcView.getLocationOnScreen(srcXY);
int[] targetXY = new int[2];
targetView.getLocationOnScreen(targetXY);
Rect srcRect = new Rect(srcXY[0], srcXY[1], srcXY[0]+srcView.getWidth(), srcXY[1]+srcView.getHeight());
Rect targetRect = new Rect(targetXY[0], targetXY[1], targetXY[0]+targetView.getWidth(), targetXY[1]+targetView.getHeight());
flyAnimation(activity, srcRect, targetRect, animationBitmap);
}
/*
* activity:傳入的帶有動畫層的Activity
* srcRect:購物車動畫的起點矩形區域
* targetRect:購物車動畫的終點矩形區域
* animationBitmap:顯示在動畫層上的位圖數據
*/
public static void flyAnimation(Activity activity, Rect srcRect, final Rect targetRect, Bitmap animationBitmap) {
if (srcRect == null || targetRect == null) {
return;
}
int[] srcXY = new int[2];
srcXY[0] = srcRect.left;
srcXY[1] = srcRect.top;
/*獲取系統動畫層的RelativeLayout*/
final RelativeLayout animationRl= (RelativeLayout) ((MainActivity) activity).getAnimationLayout();
final ImageView animationIv = new ImageView(activity);
animationIv.setImageBitmap(animationBitmap);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(srcRect.width(), srcRect.height());
params.leftMargin = srcXY[0];
params.topMargin = srcXY[1]-getStatusBarHeight(activity);
animationRl.addView(animationIv, params);
/*等待setLayoutParams值完全生效*/
animationIv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@SuppressWarnings("deprecation") @Override
public void onGlobalLayout() {
animationIv.getViewTreeObserver().removeGlobalOnLayoutListener(this);
int targetWidth = targetRect.width();
int targetHeight = targetRect.height();
int[] targetXY = new int[2];
targetXY[0] = targetRect.left;
targetXY[1] = targetRect.top;
int animationIvWidth = animationIv.getWidth();
int animationIvHeight = animationIv.getHeight();
int[] animationIvXY = new int[2];
animationIv.getLocationOnScreen(animationIvXY);
AnimatorSet aSet = new AnimatorSet();
ObjectAnimator scaleXOA = ObjectAnimator.ofFloat(animationIv, "scaleX", 1.0f, 0f);
ObjectAnimator scaleYOA = ObjectAnimator.ofFloat(animationIv, "scaleY", 1.0f, 0f);
ObjectAnimator translationXOA = ObjectAnimator.ofFloat(animationIv, "translationX", 0,
targetXY[0] + targetWidth / 2.0f - (animationIvXY[0] + animationIvWidth / 2.0f));
ObjectAnimator translationYOA = ObjectAnimator.ofFloat(animationIv, "translationY", 0,
targetXY[1] + targetHeight / 2.0f - (animationIvXY[1] + animationIvHeight / 2.0f));
aSet.playTogether(scaleXOA);
aSet.playTogether(scaleYOA);
aSet.playTogether(translationXOA);
aSet.playTogether(translationYOA);
aSet.setTarget(animationIv);
aSet.setDuration(1000);
aSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
/*位移縮放動畫執行完畢*/
new Handler().post(new Runnable() {
public void run() {
animationRl.removeAllViews();
isFlyAnimationWorking = false;
}
});
}
});
aSet.start();
isFlyAnimationWorking = true;
}
});
}
/*獲取視頻的第一幀,用於對視頻做動畫,建議在異步線程中提前取短視頻的第一幀用於飛出動畫*/
public static Bitmap getVideoFrame(String path) {
MediaMetadataRetriever media = new MediaMetadataRetriever();
try {
media.setDataSource(path);
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
return media.getFrameAtTime();
}
/*獲取狀態欄的高度*/
public static int getStatusBarHeight(Activity activity) {
Resources resources = activity.getResources();
int resourceId = resources.getIdentifier("status_bar_height", "dimen","android");
int height = resources.getDimensionPixelSize(resourceId);
return height;
}
/*獲取View的截圖*/
public static Bitmap getBitmapFromView(View v) {
Bitmap b = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.RGB_565);
Canvas c = new Canvas(b);
v.layout(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
Drawable bgDrawable = v.getBackground();
if (bgDrawable != null)
bgDrawable.draw(c);
else
c.drawColor(Color.WHITE);
v.draw(c);
return b;
}
/*清空動畫層上的所有動畫View*/
public static void clearView(Activity activity) {
RelativeLayout animationRl= (RelativeLayout) ((MainActivity) activity).getAnimationLayout();
animationRl.removeAllViews();
}
}
需要動畫的時候只要呼叫AnimationHelper中的靜態方法就可以了,就像空中支援一樣,是不是很嗨?!
最終效果:
(寫的不好, 還請多多包涵)
源碼下載: AnimationAirHelper.tar.gz