长按应用程序实现拖动它到桌面(workspace)或从桌面删除:
重要类简介
public class DeleteZone extends ImageView implements DropTarget, DragController.DragListener;
public class FolderIcon extends BubbleTextView implements DropTarget;
public class UserFolder extends Folder implements DropTarget;
public class Workspace extends ViewGroup implements DropTarget, DragSource, DragScroller;
public class AllAppsGridView extends GridView implements AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener, DragSource
launcher的根布局文件launcher.xml
launcher.xml布局如下:
<com.android.launcher.DragLayer android:id="@+id/drag_layer"......>
<!-- The workspace contains 3 screens of cells -->
<com.android.launcher.Workspace
android:id="@+id/workspace"......>
<include android:id="@+id/cell1" layout="@layout/workspace_screen" />
<include android:id="@+id/cell2" layout="@layout/workspace_screen" />
<include android:id="@+id/cell3" layout="@layout/workspace_screen" />
</com.android.launcher.Workspace>
<SlidingDrawer
android:id="@+id/drawer"
android:handle="@+id/all_apps"
android:content="@+id/content">
<com.android.launcher.HandleView
android:id="@id/all_apps"......./>
<com.android.launcher.AllAppsGridView
android:id="@id/content"................../>
</SlidingDrawer>
<com.android.launcher.DeleteZone
android:id="@+id/delete_zone".................. />
</com.android.launcher.DragLayer>
它的根元素是public class DragLayer extends FrameLayout implementsDragController
public interface DragController {
/*DragListener是给删除回收站(DeleteZone)实现的接口,拖动app item的时候删除回收站(DeleteZone)会实现onDragStart(),同时它可见;结束的时候onDragEnd(),DeleteZone再次隐藏起来
*/
interface DragListener {
void onDragStart(View v, DragSource source, Object info, int dragAction);
void onDragEnd();
}
public static int DRAG_ACTION_MOVE = 0;
public static int DRAG_ACTION_COPY = 1;
void startDrag(View v, DragSource source, Object info, int dragAction);
void setDragListener(DragListener l);
void removeDragListener(DragListener l);
}
public class DeleteZone extends ImageView implements DropTarget, DragController.DragListener
DeleteZone通过实现DragController.DragListener的onDragStart(),onDragEnd()的两个接口
public void onDragStart(View v, DragSource source, Object info, int dragAction) {
setVisibility(VISIBLE); //可见
}
public void onDragEnd() {
setVisibility(GONE);//再次隐藏
}
DragLayer通过接口setDragListener,将DeleteZone应用到内部成员mListener
说几个DragLayer内部几个接口变量:
DrogTarget拖动app_icon的时候,最终放置(接受)它的object
DeleteZone(垃圾回收筒),Workspace(桌面),FolderIcon/UserFolder(文件夹)都是可以放置app_icon的地方,所以它们都implement DropTarget
public interface DropTarget {
void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo);
void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo);
void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo);
void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo);
boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo);
Rect estimateDropLocation(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo, Rect recycle);
}
DragSource拖动来源的object,它可以是AllAppsGridView,Folder,Workspace
public interface DragSource {
void setDragger(DragController dragger);
void onDropCompleted(View target, boolean success);
}
在AllAppsGridView界面长按么个app_icon
....AllAppsGridView .....{
public boolean onItemLongClick() {
..........
mDragger.startDrag(view, this, app, DragController.DRAG_ACTION_COPY); //DragLayer开始拖动
mLauncher.closeAllApplications(); //关闭AllAppsGridView界面,切换到workspace
..........
}
}
若是在workspace界面长按么个app_icon
....Launcher .....{
public boolean onLongClick(View v) {
....
....
}
}
看看DragLayer.startDrag()做了什么,
DragLayer ...{
startDrag(...){
.........
mListener.onDragStart(v, source, dragInfo, dragAction); //调用垃圾筒listener(DeleteZone)接口onDragStart(),DeleteZone会将自己setVisibility(VISIBLE);
mDragBitmap = Bitmap.createBitmap(viewBitmap, 0, 0, width, height, scale, true); //创建一个拖动过程中,跟随拖动坐标浮动的app_icon
mDragSource = source; //设置拖动的源object,是AllAppsGridView,还是Workspace,Folder,其它
mDragInfo = dragInfo; //记录长按的那个app_icon相关信息
............
if (dropTarget != null) {
if (mLastDropTarget == dropTarget) {
dropTarget.onDragOver(mDragSource, coordinates[0], coordinates[1],
(int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo);
} else {
if (mLastDropTarget != null) {
mLastDropTarget.onDragExit(mDragSource, coordinates[0], coordinates[1],
(int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo);
}
dropTarget.onDragEnter(mDragSource, coordinates[0], coordinates[1],
(int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo);
}
} else {
if (mLastDropTarget != null) {
mLastDropTarget.onDragExit(mDragSource, coordinates[0], coordinates[1],
(int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo);
}
}
removeCallbacks(mScrollRunnable);
if (mShouldDrop) {
drop(x, y); // 添加到桌面(workspace)/文件夹(Folder)/垃圾筒(DeleteZone)
mShouldDrop = false;
}
endDrag(); // mListener.onDragEnd() 垃圾筒再次隐藏起来
break;
case MotionEvent.ACTION_CANCEL:
endDrag();
final int[] coordinates = mDropCoordinates;
DropTarget dropTarget = findDropTarget((int) x, (int) y, coordinates); // 查找最终接受app_icon的DropTarget(workspace,folder,deleteZone),以workspace为最终的 //droptarget,看看workspace做了什么,转到Workspace的类
if (dropTarget != null) {
dropTarget.onDragExit(mDragSource, coordinates[0], coordinates[1],
(int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo);
if (dropTarget.acceptDrop(mDragSource, coordinates[0], coordinates[1],
(int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo)) {
dropTarget.onDrop(mDragSource, coordinates[0], coordinates[1],
(int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo);
mDragSource.onDropCompleted((View) dropTarget, true);
return true;
} else {
mDragSource.onDropCompleted((View) dropTarget, false);
return true;
}
}
return false;
}
private int mDirection;
ScrollRunnable() {
}
public void run() {
if (mDragScroller != null) {
mDrawEstimated = false;
if (mDirection == SCROLL_LEFT) {
mDragScroller.scrollLeft(); //mDragScroller引用到workspace实例,它实现workspace的左右滚动
} else {
mDragScroller.scrollRight();
}
mScrollState = SCROLL_OUTSIDE_ZONE;
}
}
void setDirection(int direction) {
mDirection = direction;
}
}
}
class Workspace {
public boolean acceptDrop(DragSource source, int x, int y, //看看是否有空间来放app_icon
int xOffset, int yOffset, Object dragInfo) {
final CellLayout layout = getCurrentDropLayout();
final CellLayout.CellInfo cellInfo = mDragInfo;
final int spanX = cellInfo == null ? 1 : cellInfo.spanX;
final int spanY = cellInfo == null ? 1 : cellInfo.spanY;
if (mVacantCache == null) {
final View ignoreView = cellInfo == null ? null : cellInfo.cell;
mVacantCache = layout.findAllVacantCells(null, ignoreView);
}
return mVacantCache.findCellForSpan(mTempEstimate, spanX, spanY, false);
}
public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) {
final CellLayout cellLayout = getCurrentDropLayout();
if (source != this) { //拖动的app_icon是否是从workspace中拖动来的,如从AllappsGridView拖动来的app_icon就走这个分支
onDropExternal(x - xOffset, y - yOffset, dragInfo, cellLayout); //添加到数据库
} else {
// Move internally workspace内部拖动,移动app_icon的位置
if (mDragInfo != null) {
final View cell = mDragInfo.cell;
if (mCurrentScreen != mDragInfo.screen) {
final CellLayout originalCellLayout = (CellLayout) getChildAt(mDragInfo.screen);
originalCellLayout.removeView(cell);
cellLayout.addView(cell);
}
mTargetCell = estimateDropCell(x - xOffset, y - yOffset,
mDragInfo.spanX, mDragInfo.spanY, cell, cellLayout, mTargetCell);
cellLayout.onDropChild(cell, mTargetCell);
LauncherModel.moveItemInDatabase(mLauncher, info,
LauncherSettings.Favorites.CONTAINER_DESKTOP, mCurrentScreen, lp.cellX, lp.cellY);
}
}
}
}
当在workspace上添加一个app_icon的时,最终app_icon用的布局文件layout下的application.xml
<com.android.launcher.BubbleTextView xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/WorkspaceIcon.Portrait" />
class BubbleTextView extends TextView
BubbleTextView是在TextView的背景画一个透明汽泡