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,主要是重载了两个函数,这两个被重载的函数的功能如下: