給你的動畫加上翅膀-動畫空中支援方式(Android全屏動畫)

我們知道在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


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