在完整的讲解了拖拽流程之后,或许还有一个疑问:dragOver是被谁调用的?
点击进入click,然后处理完成,长按进入onlongclick处理完成,这两者都是view的接口。
那么,drag的过程中,需要一直读取手指的位置,这些操作自然也是view的接口View.OnDragListener。Launcher8.0有一个类叫做PinItemDragListener专门用来处理drag相关的操作。其中有个类ondrag,表示view进入了drag模式。
本方法最终返回 mDragController.onDragEven;
public boolean onDrag(View view, DragEvent event) {
if (mLauncher == null || mDragController == null) {
postCleanup();
return false;
}
if (event.getAction() == DragEvent.ACTION_DRAG_STARTED) {
if (onDragStart(event)) {
return true;
} else {
postCleanup();
return false;
}
}
return mDragController.onDragEvent(mDragStartTime, event);
}
而onDragEvent实际进入mDragDriver.onDragEvent
public boolean onDragEvent(long dragStartTime, DragEvent event) {
mFlingToDeleteHelper.recordDragEvent(dragStartTime, event);
return mDragDriver != null && mDragDriver.onDragEvent(event);
}
而这个dragDriver的OndragEvent则是详细的记录下每次的参数
public boolean onDragEvent (DragEvent event) {
final int action = event.getAction();
switch (action) {
//起始的手指位置
case DragEvent.ACTION_DRAG_STARTED:
mLastX = event.getX();
mLastY = event.getY();
return true;
case DragEvent.ACTION_DRAG_ENTERED:
return true;
//移动时的位置
case DragEvent.ACTION_DRAG_LOCATION:
mLastX = event.getX();
mLastY = event.getY();
mEventListener.onDriverDragMove(event.getX(), event.getY());
return true;
//松手时的位置
case DragEvent.ACTION_DROP:
mLastX = event.getX();
mLastY = event.getY();
mEventListener.onDriverDragMove(event.getX(), event.getY());
mEventListener.onDriverDragEnd(mLastX, mLastY);
return true;
case DragEvent.ACTION_DRAG_EXITED:
mEventListener.onDriverDragExitWindow();
return true;
case DragEvent.ACTION_DRAG_ENDED:
mEventListener.onDriverDragCancel();
return true;
default:
return false;
}
}
我们重点关注move的方法
public void onDriverDragMove(float x, float y) {
final int[] dragLayerPos = getClampedDragLayerPos(x, y);
handleMoveEvent(dragLayerPos[0], dragLayerPos[1]);
}
于是我们看到一个我们非常熟悉的方法,是startdrag流程,的必备方法handleMoveEvent、这个方法里面中途的 checkTouchMove(dropTarget)就是workspace、folder、button的dragEnter、dragOver、ondrop的调用方法。而结尾的callOnDragStart(),则是ondragstart和dragonend的调用方法。
private void handleMoveEvent(int x, int y) {
mDragObject.dragView.move(x, y);
final int[] coordinates = mCoordinatesTemp;
DropTarget dropTarget = findDropTarget(x, y, coordinates);
mDragObject.x = coordinates[0];
mDragObject.y = coordinates[1];
checkTouchMove(dropTarget);
mDistanceSinceScroll += Math.hypot(mLastTouch[0] - x, mLastTouch[1] - y);
mLastTouch[0] = x;
mLastTouch[1] = y;
if (mIsInPreDrag && mOptions.preDragCondition != null
&& mOptions.preDragCondition.shouldStartDrag(mDistanceSinceScroll)) {
callOnDragStart();
}
}
总结:用户能够进行的事件操作一共有4种,点击,滑动,长按,拖拽。
点击主要是识别点击的目标,然后进行对应的操作。
滑动是在GroupView才能进行的操作。
长按是onlongclick,分为
长按无效(例:在overView模式,点击两个页面之间的空白,还是保留在overView模式)
长按和点击一样(例:长按allapp入口按键)
长按切换模式(例:进入overviewmode)
长按到拖拽
拖拽大部分拖拽都进入workspace拖拽,onlongclick进入的拖拽首先调用handleMoveEvent。而后draglistener继续监听用户的操作继续调用handleMoveEvent保证拖拽的后续完成。
完成了启动流程和拖拽操作,最后还剩下的部分是通知部分,也就是当其他应用变化时,Launcher跟随的一些变化,这样一个完整的Launcher就完成了。