DeleteZone是launcher中比較簡單的一部分,其操作為
- 長按案頭上某個表徵圖後,會出現如下內容:1)dock欄消失;2)原dock欄位置出現一個垃圾箱圖案;
- 將該表徵圖拖動到垃圾箱位置後,會發現如下內容:1)垃圾箱表徵圖變為開啟;2)垃圾箱周圍出現一片紅色地區;3)表徵圖變為紅色;
- 將該表徵圖放到垃圾箱位置後,該表徵圖會被從案頭中刪除;
查看DeleteZone的源碼,只要搞清楚了以上3個步驟是如何?的,那麼就理解了他的代碼了。
1)建構函式
public DeleteZone(Context context, AttributeSet attrs) { this(context, attrs, 0); } public DeleteZone(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); final int srcColor = context.getResources().getColor(R.color.delete_color_filter); mTrashPaint.setColorFilter(new PorterDuffColorFilter(srcColor, PorterDuff.Mode.SRC_ATOP)); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DeleteZone, defStyle, 0); mOrientation = a.getInt(R.styleable.DeleteZone_direction, ORIENTATION_HORIZONTAL); a.recycle(); } @Override protected void onFinishInflate() { super.onFinishInflate(); mTransition = (TransitionDrawable) getDrawable(); }
這裡主要完成三項工作:1)構造對象;2)建立紅色地區的濾鏡顏色為紅色;3)判斷方向,這個是在launcher.xml中設定的方向。
<com.xuxm.demo.launcher.DeleteZone android:id="@+id/delete_zone" android:layout_width="@dimen/delete_zone_size" android:layout_height="@dimen/delete_zone_size" android:paddingTop="@dimen/delete_zone_padding" android:layout_gravity="top|center_horizontal" android:scaleType="center" android:src="@drawable/delete_zone_selector" android:visibility="invisible" launcher:direction="horizontal" />
同時需要注意到這裡的圖片並不是一張圖片,而是一個TransitionDrawable,其內容為:
<transition xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/trashcan" /> <item android:drawable="@drawable/trashcan_hover" /></transition>
這裡,他可以動態切換顯示的圖片,這也是你看到的垃圾箱關閉與開啟兩種顯示方式的根源。其實現在這幾個函數中實現:
public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset, DragView dragView, Object dragInfo) { mTransition.reverseTransition(TRANSITION_DURATION); dragView.setPaint(mTrashPaint); } public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset, DragView dragView, Object dragInfo) { } public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset, DragView dragView, Object dragInfo) { mTransition.reverseTransition(TRANSITION_DURATION); dragView.setPaint(null); }
這裡,當被拖動表徵圖進入到DeleteZone地區時,表徵圖變為垃圾箱開啟中狀態,如果表徵圖離開了DeleteZone地區時,垃圾箱恢複為垃圾箱關閉狀態;dragView.setPaint(mTrashPaint);這一句是設定被拖動表徵圖顯示為紅色。
2)刪除表徵圖 當你將表徵圖放到垃圾箱地區後,就會刪除該表徵圖。這裡需要區別不同的表徵圖來源區域和不同的表徵圖類型,分別進行刪除。如果是對於檔案夾,需要先將檔案夾中的內容刪除,然後再刪除該檔案夾。
public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, DragView dragView, Object dragInfo) { final ItemInfo item = (ItemInfo) dragInfo; if (item.container == -1) return; if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) { if (item instanceof LauncherAppWidgetInfo) { mLauncher.removeAppWidget((LauncherAppWidgetInfo) item); } } else { if (source instanceof UserFolder) { final UserFolder userFolder = (UserFolder) source; final UserFolderInfo userFolderInfo = (UserFolderInfo) userFolder.getInfo(); // Item must be a ShortcutInfo otherwise it couldn't have been in the folder // in the first place. userFolderInfo.remove((ShortcutInfo)item); } } if (item instanceof UserFolderInfo) { final UserFolderInfo userFolderInfo = (UserFolderInfo)item; LauncherModel.deleteUserFolderContentsFromDatabase(mLauncher, userFolderInfo); mLauncher.removeFolder(userFolderInfo); } else if (item instanceof LauncherAppWidgetInfo) { final LauncherAppWidgetInfo launcherAppWidgetInfo = (LauncherAppWidgetInfo) item; final LauncherAppWidgetHost appWidgetHost = mLauncher.getAppWidgetHost(); if (appWidgetHost != null) { final int appWidgetId = launcherAppWidgetInfo.appWidgetId; // Deleting an app widget ID is a void call but writes to disk before returning // to the caller... new Thread("deleteAppWidgetId") { public void run() { appWidgetHost.deleteAppWidgetId(launcherAppWidgetInfo.appWidgetId); } }.start(); } } LauncherModel.deleteItemFromDatabase(mLauncher, item); }
之前在測試公司產品時,發現直接將表徵圖從檔案夾中直接拖動到垃圾箱刪除後,會發現檔案夾內顯示出現問題,究其原因就是未考慮到直接從檔案夾中刪除中的問題。
3)長按表徵圖開始拖動及結束拖動
public void onDragStart(DragSource source, Object info, int dragAction) { final ItemInfo item = (ItemInfo) info; if (item != null) { mTrashMode = true; createAnimations(); final int[] location = mLocation; getLocationOnScreen(location); /** * mRight\mLeft\mBottom\mTop屬保護域, * 需通過getRight()\getLeft()\getBottom()\getTop()來訪問 * modify by author */ mRegion.set(location[0], location[1], location[0] + getRight() - getLeft(), location[1] + getBottom() - getTop()); mDragController.setDeleteRegion(mRegion); mTransition.resetTransition(); startAnimation(mInAnimation); mHandle.startAnimation(mHandleOutAnimation); setVisibility(VISIBLE); } }
之類首先獲得垃圾箱表徵圖的地區大小,據此設定DeleteZone位置的地區,同時初始化動畫對象createAnimations()。
public void onDragEnd() { if (mTrashMode) { mTrashMode = false; mDragController.setDeleteRegion(null); startAnimation(mOutAnimation); mHandle.startAnimation(mHandleInAnimation); setVisibility(GONE); } }
取消拖動地區效果,並且將dock欄回複,隱藏垃圾箱;4)初始化動畫
private void createAnimations() { if (mInAnimation == null) { mInAnimation = new FastAnimationSet(); final AnimationSet animationSet = mInAnimation; animationSet.setInterpolator(new AccelerateInterpolator()); animationSet.addAnimation(new AlphaAnimation(0.0f, 1.0f)); if (mOrientation == ORIENTATION_HORIZONTAL) { animationSet.addAnimation(new TranslateAnimation(Animation.ABSOLUTE, 0.0f, Animation.ABSOLUTE, 0.0f, Animation.RELATIVE_TO_SELF, 1.0f, Animation.RELATIVE_TO_SELF, 0.0f)); } else { animationSet.addAnimation(new TranslateAnimation(Animation.RELATIVE_TO_SELF, 1.0f, Animation.RELATIVE_TO_SELF, 0.0f, Animation.ABSOLUTE, 0.0f, Animation.ABSOLUTE, 0.0f)); } animationSet.setDuration(ANIMATION_DURATION); } if (mHandleInAnimation == null) { mHandleInAnimation = new AlphaAnimation(0.0f, 1.0f); mHandleInAnimation.setDuration(ANIMATION_DURATION); } if (mOutAnimation == null) { mOutAnimation = new FastAnimationSet(); final AnimationSet animationSet = mOutAnimation; animationSet.setInterpolator(new AccelerateInterpolator()); animationSet.addAnimation(new AlphaAnimation(1.0f, 0.0f)); if (mOrientation == ORIENTATION_HORIZONTAL) { animationSet.addAnimation(new FastTranslateAnimation(Animation.ABSOLUTE, 0.0f, Animation.ABSOLUTE, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 1.0f)); } else { animationSet.addAnimation(new FastTranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 1.0f, Animation.ABSOLUTE, 0.0f, Animation.ABSOLUTE, 0.0f)); } animationSet.setDuration(ANIMATION_DURATION); } if (mHandleOutAnimation == null) { mHandleOutAnimation = new AlphaAnimation(1.0f, 0.0f); mHandleOutAnimation.setFillAfter(true); mHandleOutAnimation.setDuration(ANIMATION_DURATION); } }
這裡主要設定三個動畫對象,dock隱藏動畫,mHandleInAnimation和mHandleOutAnimation;垃圾箱表徵圖動畫對象mInAnimation和mOutAnimation;
5)自訂Animation這裡自訂了兩個Animation,主要是重載了兩個函數,這兩個被重載的函數的功能如下: