Android-->Launcher拖拽事件详解【androidICS4.0--Launcher系列二】
2012-07-16 18:02
633 查看
AndroidICS4.0版本的launcher拖拽的流程,基本和2.3的相似。就是比2.3写的封装的接口多了一些,比如删除类的写法就多了个类。等等。4.0的改变有一些,但是不是特别大。这个月一直在改动Launcher的缩略图的效果,4.0的缩略图的功能没有实现,还得从2.3的Launcher中摘出来。通过做这个缩略图对Launcher的模块有一点点了解,拿来分享一下Launcher拖拽的工作流程。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201707/61c17ed2eb67211a84e137429ac3f7ad.gif)
有图有真相!
![](https://oscdn.geek-share.com/Uploads/Images/Content/201705/40da226498c84c92e2ee7e86a0b4fd72.gif)
转载请标明出处:http://blog.csdn.net/wdaming1986/article/details/7671318
(1)
先来看看类之间的继承关系
![](http://my.csdn.net/uploads/201206/17/1339929258_8122.PNG)
图(1)
(2)再来看看Launcher拖拽流程的时序图
![](http://my.csdn.net/uploads/201206/17/1339929475_3267.PNG)
图(2)
下面咱们分步来解析Launcher拖拽的详细过程:
step 1 :先来看看Launcher.java这个类的onCreate()方法中的setupViews()方法中的一部分代码:
[java]
view plaincopyprint?
<STRONG> </STRONG><SPAN style="COLOR: #000000; FONT-SIZE: 16px">// Setup the workspace
mWorkspace.setHapticFeedbackEnabled(false);
mWorkspace.setOnLongClickListener(this);
mWorkspace.setup(dragController);
dragController.addDragListener(mWorkspace);</SPAN>
Workspace设置长按事件的监听交给了Launcher.java这个类了。所以在主屏上长按事件会走到Launcher.java----->
onLongClick()这个方法中去;
step 2 :接着我们来看看Launcher.java中onLongClick()的代码:
[java]
view plaincopyprint?
public boolean onLongClick(View v) {
··············
// The hotseat touch handling does not go through Workspace, and we always allow long press
// on hotseat items.
final View itemUnderLongClick = longClickCellInfo.cell;
boolean allowLongPress = isHotseatLayout(v) || mWorkspace.allowLongPress();
if (allowLongPress && !mDragController.isDragging()) {
if (itemUnderLongClick ==
null) {
// User long pressed on empty space
mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
startWallpaper();
} else {
if (!(itemUnderLongClick
instanceof Folder)) {
// User long pressed on an item
mWorkspace.startDrag(longClickCellInfo);
}
}
}
return true;
}
通过itemUnderLongClick == null 来判断,在屏幕上触发长按事件是否选中了shortcut或者widget。如果为空,就启动桌面的壁纸,else,就把拖拽事件往Workspace.java这个类传递。
Step 3 :通过mWorkspace.startDrag(longClickCellInfo),把长按事件传递给workspace来处理,具体来看代码:
[java]
view plaincopyprint?
void startDrag(CellLayout.CellInfo cellInfo) {
View child = cellInfo.cell;
// Make sure the drag was started by a long press as opposed to a long click.
if (!child.isInTouchMode()) {
return;
}
mDragInfo = cellInfo;
//隐藏拖拽的child
child.setVisibility(GONE);
child.clearFocus();
child.setPressed(false);
final Canvas canvas =
new Canvas();
// We need to add extra padding to the bitmap to make room for the glow effect
final int bitmapPadding = HolographicOutlineHelper.MAX_OUTER_BLUR_RADIUS;
// The outline is used to visualize where the item will land if dropped
mDragOutline = createDragOutline(child, canvas, bitmapPadding);
beginDragShared(child, this);
}
上面的代码主要做的工作是:把正在拖拽的这个view隐藏掉,在主屏幕上绘制一个蓝色的,大小和图标相似的一个边框,以表示能在主屏的这个位置放置。
Step 4 :接着调用beginDragShared(child, this)这个方法,代码如下:
[java]
view plaincopyprint?
public
void beginDragShared(View child, DragSource source) {
··· ···
// Clear the pressed state if necessary
if (child instanceof BubbleTextView) {
BubbleTextView icon = (BubbleTextView) child;
icon.clearPressedOrFocusedBackground();
}
mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(),
DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect);
b.recycle();
}
这个方法做的工作是:开始进行拖拽,绘制正在拖拽的图片,把拖拽的事件交给DragController来处理。
Step 5 :接着来看看mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(), DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect)这个方法,代码如下:
[java]
view plaincopyprint?
public
void startDrag(Bitmap b, int dragLayerX,
int dragLayerY,
DragSource source, Object dragInfo, int dragAction, Point dragOffset, Rect dragRegion) {
··· ···
mDragObject.dragComplete = false;
mDragObject.xOffset = mMotionDownX - (dragLayerX + dragRegionLeft);
mDragObject.yOffset = mMotionDownY - (dragLayerY + dragRegionTop);
mDragObject.dragSource = source;
mDragObject.dragInfo = dragInfo;
mVibrator.vibrate(VIBRATE_DURATION);
final DragView dragView = mDragObject.dragView =
new DragView(mLauncher, b, registrationX,
registrationY, 0, 0, b.getWidth(), b.getHeight());
if (dragOffset != null) {
dragView.setDragVisualizeOffset(new Point(dragOffset));
}
if (dragRegion !=
null) {
dragView.setDragRegion(new Rect(dragRegion));
}
dragView.show(mMotionDownX, mMotionDownY);
handleMoveEvent(mMotionDownX, mMotionDownY);
}
这个方法的作用是:计算要拖拽的view的大小,显示在workspace上,dragView.show(mMotionDownX, mMotionDownY);这个show()会根据手指的移动而移动的。然后在通过handleMoveEvent()方法来分发拖拽的目标到底在哪个目标上。DropTarget一共有3个:workspace,ButtonDropTarget(删除类),Folder;他们分别实现了DropTarget这个接口。
下面来看看这个接口有一下几个方法:
[java]
view plaincopyprint?
boolean isDropEnabled();
void onDrop(DragObject dragObject);
void onDragEnter(DragObject dragObject);
void onDragOver(DragObject dragObject);
void onDragExit(DragObject dragObject);
DropTarget getDropTargetDelegate(DragObject dragObject);
boolean acceptDrop(DragObject dragObject);
// These methods are implemented in Views
void getHitRect(Rect outRect);
void getLocationInDragLayer(int[] loc);
int getLeft();
int getTop();
这些方法不是每个类继承了DropTarget的接口,都要把每个方法都实现,这要看具体的需要来定。
另外这个接口中有个内部类-----DragObject:如下
[java]
view plaincopyprint?
class DragObject {
public int x = -1;
public int y = -1;
/** X offset from the upper-left corner of the cell to where we touched. */
public int xOffset = -1;
/** Y offset from the upper-left corner of the cell to where we touched. */
public int yOffset = -1;
/** This indicates whether a drag is in final stages, either drop or cancel. It
* differentiates onDragExit, since this is called when the drag is ending, above
* the current drag target, or when the drag moves off the current drag object.
*/
public boolean dragComplete =
false;
/** The view that moves around while you drag. */
public DragView dragView =
null;
/** The data associated with the object being dragged */
public Object dragInfo =
null;
/** Where the drag originated */
public DragSource dragSource =
null;
/** Post drag animation runnable */
public Runnable postAnimationRunnable =
null;
/** Indicates that the drag operation was cancelled */
public boolean cancelled =
false;
public DragObject() {
}
}
这个类的作用是存储一些坐标,拖拽点距离整个view左上角x轴上的距离,y轴上的距离,还有一些拖拽的信息都保存在这个类中,还有动画线程类等等。在拖拽过程中这些信息都是会用到的。
Step 6 :接着来看看handleMoveEvent()这个类,这个类频繁被调用,因为在DragLayer.java这个类中onTouchEvent()方法,最后调用的是 mDragController.onTouchEvent(ev)这个方法,长按后,移动的事件就传递到了DragController中的onTouchEvent()方法中,先来看看mDragController.onTouchEvent(ev)这个方法,代码如下:
[java]
view plaincopyprint?
/**
* Call this from a drag source view.
*/
public boolean onTouchEvent(MotionEvent ev) {
if (!mDragging) {
return false;
}
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_DOWN:
// Remember where the motion event started
mMotionDownX = dragLayerX;
mMotionDownY = dragLayerY;
if ((dragLayerX < mScrollZone) || (dragLayerX > mScrollView.getWidth() - mScrollZone)) {
mScrollState = SCROLL_WAITING_IN_ZONE;
mHandler.postDelayed(mScrollRunnable, SCROLL_DELAY);
} else {
mScrollState = SCROLL_OUTSIDE_ZONE;
}
break;
case MotionEvent.ACTION_MOVE:
handleMoveEvent(dragLayerX, dragLayerY);
break;
case MotionEvent.ACTION_UP:
// Ensure that we've processed a move event at the current pointer location.
handleMoveEvent(dragLayerX, dragLayerY);
mHandler.removeCallbacks(mScrollRunnable);
if (mDragging) {
drop(dragLayerX, dragLayerY);
}
endDrag();
break;
case MotionEvent.ACTION_CANCEL:
cancelDrag();
break;
}
return true;
}
在这个方法中清楚的可以看见handleMoveEvent()这个方法会在move,up的时候频繁地调用。
现在再来看看这个handleMoveEvent()方法,看看它的庐山真面目:
[java]
view plaincopyprint?
private void handleMoveEvent(int x,
int y) {
mDragObject.dragView.move(x, y);
// Drop on someone?
final int[] coordinates = mCoordinatesTemp;
DropTarget dropTarget = findDropTarget(x, y, coordinates);
mDragObject.x = coordinates[0];
mDragObject.y = coordinates[1];
if (dropTarget !=
null) {
DropTarget delegate = dropTarget.getDropTargetDelegate(mDragObject);
if (delegate !=
null) {
dropTarget = delegate;
}
if (mLastDropTarget != dropTarget) {
if (mLastDropTarget !=
null) {
mLastDropTarget.onDragExit(mDragObject);
}
dropTarget.onDragEnter(mDragObject);
}
dropTarget.onDragOver(mDragObject);
} else {
if (mLastDropTarget !=
null) {
mLastDropTarget.onDragExit(mDragObject);
}
}
mLastDropTarget = dropTarget;
··· ···
}
这个方法的作用:通过findDropTarget(x, y, coordinates),来判断在哪个拖拽目标里面,然后通过下面的if判断来执行不同的onDragOver,onDragExit等的方法。这样就在相应的类中去做处理,以后的事情就明朗了。这就是Launcher的拖拽事件的分发与处理,用到了MVC的思想,代码阅读起来还是比较顺利的。有图有真相。
欢迎大家留言讨论相关问题。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201707/61c17ed2eb67211a84e137429ac3f7ad.gif)
有图有真相!
![](https://oscdn.geek-share.com/Uploads/Images/Content/201705/40da226498c84c92e2ee7e86a0b4fd72.gif)
转载请标明出处:http://blog.csdn.net/wdaming1986/article/details/7671318
(1)
先来看看类之间的继承关系
图(1)
(2)再来看看Launcher拖拽流程的时序图
图(2)
下面咱们分步来解析Launcher拖拽的详细过程:
step 1 :先来看看Launcher.java这个类的onCreate()方法中的setupViews()方法中的一部分代码:
[java]
view plaincopyprint?
<STRONG> </STRONG><SPAN style="COLOR: #000000; FONT-SIZE: 16px">// Setup the workspace
mWorkspace.setHapticFeedbackEnabled(false);
mWorkspace.setOnLongClickListener(this);
mWorkspace.setup(dragController);
dragController.addDragListener(mWorkspace);</SPAN>
// Setup the workspace mWorkspace.setHapticFeedbackEnabled(false); mWorkspace.setOnLongClickListener(this); mWorkspace.setup(dragController); dragController.addDragListener(mWorkspace);
Workspace设置长按事件的监听交给了Launcher.java这个类了。所以在主屏上长按事件会走到Launcher.java----->
onLongClick()这个方法中去;
step 2 :接着我们来看看Launcher.java中onLongClick()的代码:
[java]
view plaincopyprint?
public boolean onLongClick(View v) {
··············
// The hotseat touch handling does not go through Workspace, and we always allow long press
// on hotseat items.
final View itemUnderLongClick = longClickCellInfo.cell;
boolean allowLongPress = isHotseatLayout(v) || mWorkspace.allowLongPress();
if (allowLongPress && !mDragController.isDragging()) {
if (itemUnderLongClick ==
null) {
// User long pressed on empty space
mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
startWallpaper();
} else {
if (!(itemUnderLongClick
instanceof Folder)) {
// User long pressed on an item
mWorkspace.startDrag(longClickCellInfo);
}
}
}
return true;
}
public boolean onLongClick(View v) { ·············· // The hotseat touch handling does not go through Workspace, and we always allow long press // on hotseat items. final View itemUnderLongClick = longClickCellInfo.cell; boolean allowLongPress = isHotseatLayout(v) || mWorkspace.allowLongPress(); if (allowLongPress && !mDragController.isDragging()) { if (itemUnderLongClick == null) { // User long pressed on empty space mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); startWallpaper(); } else { if (!(itemUnderLongClick instanceof Folder)) { // User long pressed on an item mWorkspace.startDrag(longClickCellInfo); } } } return true; }
通过itemUnderLongClick == null 来判断,在屏幕上触发长按事件是否选中了shortcut或者widget。如果为空,就启动桌面的壁纸,else,就把拖拽事件往Workspace.java这个类传递。
Step 3 :通过mWorkspace.startDrag(longClickCellInfo),把长按事件传递给workspace来处理,具体来看代码:
[java]
view plaincopyprint?
void startDrag(CellLayout.CellInfo cellInfo) {
View child = cellInfo.cell;
// Make sure the drag was started by a long press as opposed to a long click.
if (!child.isInTouchMode()) {
return;
}
mDragInfo = cellInfo;
//隐藏拖拽的child
child.setVisibility(GONE);
child.clearFocus();
child.setPressed(false);
final Canvas canvas =
new Canvas();
// We need to add extra padding to the bitmap to make room for the glow effect
final int bitmapPadding = HolographicOutlineHelper.MAX_OUTER_BLUR_RADIUS;
// The outline is used to visualize where the item will land if dropped
mDragOutline = createDragOutline(child, canvas, bitmapPadding);
beginDragShared(child, this);
}
void startDrag(CellLayout.CellInfo cellInfo) { View child = cellInfo.cell; // Make sure the drag was started by a long press as opposed to a long click. if (!child.isInTouchMode()) { return; } mDragInfo = cellInfo; //隐藏拖拽的child child.setVisibility(GONE); child.clearFocus(); child.setPressed(false); final Canvas canvas = new Canvas(); // We need to add extra padding to the bitmap to make room for the glow effect final int bitmapPadding = HolographicOutlineHelper.MAX_OUTER_BLUR_RADIUS; // The outline is used to visualize where the item will land if dropped mDragOutline = createDragOutline(child, canvas, bitmapPadding); beginDragShared(child, this); }
上面的代码主要做的工作是:把正在拖拽的这个view隐藏掉,在主屏幕上绘制一个蓝色的,大小和图标相似的一个边框,以表示能在主屏的这个位置放置。
Step 4 :接着调用beginDragShared(child, this)这个方法,代码如下:
[java]
view plaincopyprint?
public
void beginDragShared(View child, DragSource source) {
··· ···
// Clear the pressed state if necessary
if (child instanceof BubbleTextView) {
BubbleTextView icon = (BubbleTextView) child;
icon.clearPressedOrFocusedBackground();
}
mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(),
DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect);
b.recycle();
}
public void beginDragShared(View child, DragSource source) { ··· ··· // Clear the pressed state if necessary if (child instanceof BubbleTextView) { BubbleTextView icon = (BubbleTextView) child; icon.clearPressedOrFocusedBackground(); } mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(), DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect); b.recycle(); }
这个方法做的工作是:开始进行拖拽,绘制正在拖拽的图片,把拖拽的事件交给DragController来处理。
Step 5 :接着来看看mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(), DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect)这个方法,代码如下:
[java]
view plaincopyprint?
public
void startDrag(Bitmap b, int dragLayerX,
int dragLayerY,
DragSource source, Object dragInfo, int dragAction, Point dragOffset, Rect dragRegion) {
··· ···
mDragObject.dragComplete = false;
mDragObject.xOffset = mMotionDownX - (dragLayerX + dragRegionLeft);
mDragObject.yOffset = mMotionDownY - (dragLayerY + dragRegionTop);
mDragObject.dragSource = source;
mDragObject.dragInfo = dragInfo;
mVibrator.vibrate(VIBRATE_DURATION);
final DragView dragView = mDragObject.dragView =
new DragView(mLauncher, b, registrationX,
registrationY, 0, 0, b.getWidth(), b.getHeight());
if (dragOffset != null) {
dragView.setDragVisualizeOffset(new Point(dragOffset));
}
if (dragRegion !=
null) {
dragView.setDragRegion(new Rect(dragRegion));
}
dragView.show(mMotionDownX, mMotionDownY);
handleMoveEvent(mMotionDownX, mMotionDownY);
}
public void startDrag(Bitmap b, int dragLayerX, int dragLayerY, DragSource source, Object dragInfo, int dragAction, Point dragOffset, Rect dragRegion) { ··· ··· mDragObject.dragComplete = false; mDragObject.xOffset = mMotionDownX - (dragLayerX + dragRegionLeft); mDragObject.yOffset = mMotionDownY - (dragLayerY + dragRegionTop); mDragObject.dragSource = source; mDragObject.dragInfo = dragInfo; mVibrator.vibrate(VIBRATE_DURATION); final DragView dragView = mDragObject.dragView = new DragView(mLauncher, b, registrationX, registrationY, 0, 0, b.getWidth(), b.getHeight()); if (dragOffset != null) { dragView.setDragVisualizeOffset(new Point(dragOffset)); } if (dragRegion != null) { dragView.setDragRegion(new Rect(dragRegion)); } dragView.show(mMotionDownX, mMotionDownY); handleMoveEvent(mMotionDownX, mMotionDownY); }
这个方法的作用是:计算要拖拽的view的大小,显示在workspace上,dragView.show(mMotionDownX, mMotionDownY);这个show()会根据手指的移动而移动的。然后在通过handleMoveEvent()方法来分发拖拽的目标到底在哪个目标上。DropTarget一共有3个:workspace,ButtonDropTarget(删除类),Folder;他们分别实现了DropTarget这个接口。
下面来看看这个接口有一下几个方法:
[java]
view plaincopyprint?
boolean isDropEnabled();
void onDrop(DragObject dragObject);
void onDragEnter(DragObject dragObject);
void onDragOver(DragObject dragObject);
void onDragExit(DragObject dragObject);
DropTarget getDropTargetDelegate(DragObject dragObject);
boolean acceptDrop(DragObject dragObject);
// These methods are implemented in Views
void getHitRect(Rect outRect);
void getLocationInDragLayer(int[] loc);
int getLeft();
int getTop();
boolean isDropEnabled(); void onDrop(DragObject dragObject); void onDragEnter(DragObject dragObject); void onDragOver(DragObject dragObject); void onDragExit(DragObject dragObject); DropTarget getDropTargetDelegate(DragObject dragObject); boolean acceptDrop(DragObject dragObject); // These methods are implemented in Views void getHitRect(Rect outRect); void getLocationInDragLayer(int[] loc); int getLeft(); int getTop();
这些方法不是每个类继承了DropTarget的接口,都要把每个方法都实现,这要看具体的需要来定。
另外这个接口中有个内部类-----DragObject:如下
[java]
view plaincopyprint?
class DragObject {
public int x = -1;
public int y = -1;
/** X offset from the upper-left corner of the cell to where we touched. */
public int xOffset = -1;
/** Y offset from the upper-left corner of the cell to where we touched. */
public int yOffset = -1;
/** This indicates whether a drag is in final stages, either drop or cancel. It
* differentiates onDragExit, since this is called when the drag is ending, above
* the current drag target, or when the drag moves off the current drag object.
*/
public boolean dragComplete =
false;
/** The view that moves around while you drag. */
public DragView dragView =
null;
/** The data associated with the object being dragged */
public Object dragInfo =
null;
/** Where the drag originated */
public DragSource dragSource =
null;
/** Post drag animation runnable */
public Runnable postAnimationRunnable =
null;
/** Indicates that the drag operation was cancelled */
public boolean cancelled =
false;
public DragObject() {
}
}
class DragObject { public int x = -1; public int y = -1; /** X offset from the upper-left corner of the cell to where we touched. */ public int xOffset = -1; /** Y offset from the upper-left corner of the cell to where we touched. */ public int yOffset = -1; /** This indicates whether a drag is in final stages, either drop or cancel. It * differentiates onDragExit, since this is called when the drag is ending, above * the current drag target, or when the drag moves off the current drag object. */ public boolean dragComplete = false; /** The view that moves around while you drag. */ public DragView dragView = null; /** The data associated with the object being dragged */ public Object dragInfo = null; /** Where the drag originated */ public DragSource dragSource = null; /** Post drag animation runnable */ public Runnable postAnimationRunnable = null; /** Indicates that the drag operation was cancelled */ public boolean cancelled = false; public DragObject() { } }
这个类的作用是存储一些坐标,拖拽点距离整个view左上角x轴上的距离,y轴上的距离,还有一些拖拽的信息都保存在这个类中,还有动画线程类等等。在拖拽过程中这些信息都是会用到的。
Step 6 :接着来看看handleMoveEvent()这个类,这个类频繁被调用,因为在DragLayer.java这个类中onTouchEvent()方法,最后调用的是 mDragController.onTouchEvent(ev)这个方法,长按后,移动的事件就传递到了DragController中的onTouchEvent()方法中,先来看看mDragController.onTouchEvent(ev)这个方法,代码如下:
[java]
view plaincopyprint?
/**
* Call this from a drag source view.
*/
public boolean onTouchEvent(MotionEvent ev) {
if (!mDragging) {
return false;
}
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_DOWN:
// Remember where the motion event started
mMotionDownX = dragLayerX;
mMotionDownY = dragLayerY;
if ((dragLayerX < mScrollZone) || (dragLayerX > mScrollView.getWidth() - mScrollZone)) {
mScrollState = SCROLL_WAITING_IN_ZONE;
mHandler.postDelayed(mScrollRunnable, SCROLL_DELAY);
} else {
mScrollState = SCROLL_OUTSIDE_ZONE;
}
break;
case MotionEvent.ACTION_MOVE:
handleMoveEvent(dragLayerX, dragLayerY);
break;
case MotionEvent.ACTION_UP:
// Ensure that we've processed a move event at the current pointer location.
handleMoveEvent(dragLayerX, dragLayerY);
mHandler.removeCallbacks(mScrollRunnable);
if (mDragging) {
drop(dragLayerX, dragLayerY);
}
endDrag();
break;
case MotionEvent.ACTION_CANCEL:
cancelDrag();
break;
}
return true;
}
/** * Call this from a drag source view. */ public boolean onTouchEvent(MotionEvent ev) { if (!mDragging) { return false; } 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_DOWN: // Remember where the motion event started mMotionDownX = dragLayerX; mMotionDownY = dragLayerY; if ((dragLayerX < mScrollZone) || (dragLayerX > mScrollView.getWidth() - mScrollZone)) { mScrollState = SCROLL_WAITING_IN_ZONE; mHandler.postDelayed(mScrollRunnable, SCROLL_DELAY); } else { mScrollState = SCROLL_OUTSIDE_ZONE; } break; case MotionEvent.ACTION_MOVE: handleMoveEvent(dragLayerX, dragLayerY); break; case MotionEvent.ACTION_UP: // Ensure that we've processed a move event at the current pointer location. handleMoveEvent(dragLayerX, dragLayerY); mHandler.removeCallbacks(mScrollRunnable); if (mDragging) { drop(dragLayerX, dragLayerY); } endDrag(); break; case MotionEvent.ACTION_CANCEL: cancelDrag(); break; } return true; }
在这个方法中清楚的可以看见handleMoveEvent()这个方法会在move,up的时候频繁地调用。
现在再来看看这个handleMoveEvent()方法,看看它的庐山真面目:
[java]
view plaincopyprint?
private void handleMoveEvent(int x,
int y) {
mDragObject.dragView.move(x, y);
// Drop on someone?
final int[] coordinates = mCoordinatesTemp;
DropTarget dropTarget = findDropTarget(x, y, coordinates);
mDragObject.x = coordinates[0];
mDragObject.y = coordinates[1];
if (dropTarget !=
null) {
DropTarget delegate = dropTarget.getDropTargetDelegate(mDragObject);
if (delegate !=
null) {
dropTarget = delegate;
}
if (mLastDropTarget != dropTarget) {
if (mLastDropTarget !=
null) {
mLastDropTarget.onDragExit(mDragObject);
}
dropTarget.onDragEnter(mDragObject);
}
dropTarget.onDragOver(mDragObject);
} else {
if (mLastDropTarget !=
null) {
mLastDropTarget.onDragExit(mDragObject);
}
}
mLastDropTarget = dropTarget;
··· ···
}
private void handleMoveEvent(int x, int y) { mDragObject.dragView.move(x, y); // Drop on someone? final int[] coordinates = mCoordinatesTemp; DropTarget dropTarget = findDropTarget(x, y, coordinates); mDragObject.x = coordinates[0]; mDragObject.y = coordinates[1]; if (dropTarget != null) { DropTarget delegate = dropTarget.getDropTargetDelegate(mDragObject); if (delegate != null) { dropTarget = delegate; } if (mLastDropTarget != dropTarget) { if (mLastDropTarget != null) { mLastDropTarget.onDragExit(mDragObject); } dropTarget.onDragEnter(mDragObject); } dropTarget.onDragOver(mDragObject); } else { if (mLastDropTarget != null) { mLastDropTarget.onDragExit(mDragObject); } } mLastDropTarget = dropTarget; ··· ··· }
这个方法的作用:通过findDropTarget(x, y, coordinates),来判断在哪个拖拽目标里面,然后通过下面的if判断来执行不同的onDragOver,onDragExit等的方法。这样就在相应的类中去做处理,以后的事情就明朗了。这就是Launcher的拖拽事件的分发与处理,用到了MVC的思想,代码阅读起来还是比较顺利的。有图有真相。
欢迎大家留言讨论相关问题。
相关文章推荐
- Android-->Launcher拖拽事件详解【androidICS4.0--Launcher系列二】
- Android-->Launcher拖拽事件详解【androidICS4.0--Launcher系列二】
- Android-->Launcher拖拽事件详解【androidICS4.0--Launcher系列二】
- Android-->Launcher拖拽事件详解【androidICS4.0--Launcher系列二】
- Android-->Launcher拖拽事件详解【androidICS4.0--Launcher系列二】
- Android中ICS4.0Launcher中Fold的功能详解【androidICS4.0-->Launcher系列三】
- Android Launcher拖拽事件详解【android4.0--Launcher系列二】
- Android中ICS4.0Launcher中Fold的功能详解【androidICS4.0-->Launcher系列三】
- Android中ICS4.0Launcher中Fold的功能详解【androidICS4.0-->Launcher系列三】
- Android-->Launcher拖拽事件详解
- Android中ICS4.0Launcher中Fold的功能详解【androidICS4.0-->Launcher系列三】
- Android---->Allapps加载流程详解【AndroidICS4.0——>Launcher系列五】
- Android---->Allapps加载流程详解【AndroidICS4.0——>Launcher系列五】
- Android---->Allapps加载流程详解【AndroidICS4.0——>Launcher系列五】
- Launcher启动的流程图【AndroidICS4.0——>Launcher系列四】
- Launcher启动的流程图【AndroidICS4.0——>Launcher系列四】
- Android中ICS4.0源码Launcher启动流程分析【android源码Launcher系列一】
- Android中ICS4.0源码Launcher启动流程分析【android源码Launcher系列一】
- Android中ICS4.0源码Launcher启动流程分析【android源码Launcher系列一】
- Android中ICS4.0Launcher中Fold的功能详解