相关的博客:Launcher2分析——桌面(WorkSpace)图标拖拽
DragTarget为Workspace(或者是Folder),DragObject为正在拖拽的那个Item,该对象持有一个DragView 对象,这个DragView就是跟随手指动的那个View。
在桌面的视图结构中,DragLayer是Workspace和HotSeat的父视图,而CellLayout则是Workspace和HotSeat的子视图,一个CellLayout代表一页。Launcher持有DragController,DragLayer,Workspace,HotSeat,而这四个类中都持有Launcher,这个四个类就是通过Launcher互相引用的。DragController在进入拖拽模式后,发挥着主力功能,是处理拖拽相关的主要实现者
DragLayer:
继承自FrameLayout。主要负责的功能是拦截和处理与拖拽有关事件。在进入拖拽模式后,就是在长按图标后,调用Workspace的startDrag()设置mDragging标志开始一直到action_up为止。在拖拽时,首先是把CellLayout的那个快捷方式图标给隐藏了,然后把一个相同图标addView到DragLayer,也就是说跟随手指的那个图标石add到DragLayer的。DragLayer还负责在action_up后,对这个DragView(跟随手指动的)进行动画,就是从手指为止到要放到的那个位置的动画。
对于measure,layout,draw的过程没有做什么自定义,只复写了一个onLayout,也是调用父类的onLayout然后自己加了几句:
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);//调用父类的onLayout对child进行布局
int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
final FrameLayout.LayoutParams flp = (FrameLayout.LayoutParams) child.getLayoutParams();
if (flp instanceof LayoutParams) {
final LayoutParams lp = (LayoutParams) flp;
if (lp.customPosition) {//如果这个属性为true,则对该child重新layout,指定为给child要求的位置参数
child.layout(lp.x, lp.y, lp.x + lp.width, lp.y + lp.height);
}
}
}
}
分析DragLayer对进入Dragging模式后对action_move拦截:
DragLayer#onInterceptTouchEvent()->DragController#onInterceptTouchEvent()
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
if (handleTouchDown(ev, true)) {
return true;
}
}
clearAllResizeFrames();
return mDragController.onInterceptTouchEvent(ev);
}
public boolean onInterceptTouchEvent(MotionEvent ev) {
@SuppressWarnings("all") // suppress dead code warning
final boolean debug = false;
if (debug) {
Log.d(Launcher.TAG, "DragController.onInterceptTouchEvent " + ev + " mDragging="
+ mDragging);
}
// Update the velocity tracker
acquireVelocityTrackerAndAddMovement(ev);
final int action = ev.getAction();
final int[] dragLayerPos = getClampedDragLayerPos(ev.getX(), ev.getY());//获取此时如果要放下,要放到的格子左上角坐标
final int dragLayerX = dragLayerPos[0];
final int dragLayerY = dragLayerPos[1];
switch (action) {
case MotionEvent.ACTION_MOVE:
break;//如果是move事件,不做处理
case MotionEvent.ACTION_DOWN:
// Remember location of down touch
mMotionDownX = dragLayerX;
mMotionDownY = dragLayerY;
mLastDropTarget = null;
break;
case MotionEvent.ACTION_UP:
mLastTouchUpTime = System.currentTimeMillis();
if (mDragging) {
PointF vec = isFlingingToDelete(mDragObject.dragSource);//判断是否拖拽到要删除的地方
if (vec != null) {
dropOnFlingToDeleteTarget(dragLayerX, dragLayerY, vec);
} else {
drop(dragLayerX, dragLayerY);//如果不是删除,则是要把图标放到某个格子,格子的左上角坐标为对应的参数
}
}
endDrag();
break;
case MotionEvent.ACTION_CANCEL:
cancelDrag();
break;
}
return mDragging;//如果进入了拖拽模式,则返回true。就是说,只要是进入拖拽模式后的事件,都会被拦截
}
看看DragController#drop()