您的位置:首页 > 其它

Launcher简要分析:Launcher的组件拖动机制

2012-06-29 09:25 183 查看
Launcher里面我们觉得比较新颖的操作方式有几种,比如通过拖拽桌面空白区域实现桌面区域的切换,长按拖动某个快捷图标的随意拖动和位置摆放,从AllAppsSildingView中,拖动某个应用图标到桌面上实现做成快捷方式等等。这些操作时如何实现的呢? 下面我们就结合源码来初略分析下. 如果从实现的角度来说的话,实现组件的OnTouch实际的相关方法,我们就可以轻易的实现某个组件的拖拽,而在Launcher中,拖拽的场景和约束条件更多更复杂,导致了无法使用单纯的OnTouch事件来控制。 在Launcher里面实现了一种模式来服务适合Launcher相关业务的拖拽实现。我们称这种模式为Drop&
Drag模型

Drop& Drag模型

Drop&Drag模式通过定义DragSource 和 DragTarget两种接口模式,定义了整个这个拖拽过程的事件模型,从而规范了拖拽事件的处理。

DragSource:可以拖动的对象来源的容器,在launcher中主要有AllAppSildingView,Workspace等

void onDropCompleted(View target, boolean success,int x,int y); 拖拽完成时候的处理

DropTarget:可以放置被拖动的对象的容器。在launcher中有Folder,Workspace,DockBar,DeleteZone等,一个View既可以是Dragsource也可以是DropTarget

boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo); acceptDrop 函数用来判断dropTarget是否可以接受item放置在自己里面。
void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo); onDragEnter是item被拖动进入到一个dropTarget的时候的回调
void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo); onDragOver是item在上一次位置和这一次位置所处的dropTarget相同的时候的回调。
void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) onDragExit是item被拖出dropTarget时的回调
boolean onDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo); onDrop是item被放置到dropTarget时的回调

下面结合代码来看看:

DropTarget dropTarget = findDropTarget((int) x, (int) y, coordinates);
if (dropTarget != null) {
/**
* 当这一次的 target 跟上一次相同时,根据坐标来移动item
*/
if (mLastDropTarget == dropTarget) {
dropTarget.onDragOver(mDragSource, coordinates[0], coordinates[1],
(int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo);
} else {
/**
* 当上一次的位置跟这一次不同而且上一次的位置不为空,说明item移 *动出了,将上次的 View 根据上次的坐标重新排列,并根据当前坐标重排*当前的*/
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 {//如果这一次为 null ,上一次不为 null ,那么把上一次坐标位置的 cell 去掉
if (mLastDropTarget != null) {
mLastDropTarget.onDragExit(mDragSource, coordinates[0], coordinates[1],
(int) mTouchOffsetX, (int) mTouchOffsetY, mDragInfo);
}
}
//记录上次的droptarget
mLastDropTarget = dropTarget;

各个实现DragSource或者 DragTarget的组件,只要实现按自身业务要求实现相关方法即可。当然,同一个组件既可以为DragSource也可以为DragTarget.

Touch event的处理

仅仅有Drag-Drop模型是不够的,Launcher对系统的Touch event也做了相关的处理.我们知道事件处理的时候一般采用RootView先消费,根据消费结果判断是否分发给ChildView消费的。依次类推,直至到达View的最后一层。onInterceptTouchEvent(MotionEvent)拦截所有的touch事件,经过判断后分发给childview。如果onInterceptTouchEvent返回true,表示事件已经被消费掉了,无需继续转发;如果onInterceptTouchEvent返回false,表示事件需要继续转发给下一层组件.

具体判断的规则如下:

Down事件首先会传递到onInterceptTouchEvent()方法
如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return false,那么后续的move, up等事件将继续会先传递给该ViewGroup,之后才和down事件一样传递给最终的目标view的onTouchEvent()处理。
如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return true,那么后续的move, up等事件将不再传递给onInterceptTouchEvent(),而是和down事件一样传递给该ViewGroup的onTouchEvent()处理,注意,目标view将接收不到任何事件。
如果最终需要处理事件的view的onTouchEvent()返回了false,那么该事件将被传递至其上一层次的view的onTouchEvent()处理。
如果最终需要处理事件的view 的onTouchEvent()返回了true,那么后续事件将可以继续传递给该view的onTouchEvent()处理。

利用Drop& Drag模型的结合Touch Event的处理,配合CellLayout的位置单元格模式的划分,各个组件的拖动,拖入,拖出,摆放都可以轻松的实现了.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: