Launcher里面我们觉得比较新颖的操作方式有几种,比如通过拖拽桌面空白区域实现桌面区域的切换,长按拖动某个快捷图标的随意拖动和位置摆放,从AllAppsSildingView中,拖动某个应用图标到桌面上实现做成快捷方式等等。这些操作时如何实现的呢? 下面我们就结合源码来初略分析下. 如果从实现的角度来说的话,实现组件的OnTouch实际的相关方法,我们就可以轻易的实现某个组件的拖拽,而在Launcher中,拖拽的场景和约束条件更多更复杂,导致了无法使用单纯的OnTouch事件来控制。 在Launcher里面实现了一种模式来服务适合Launcher相关业务的拖拽实现。我们称这种模式为Drop& Drag模型
Drop&Drag模式通过定义DragSource 和 DragTarget两种接口模式,定义了整个这个拖拽过程的事件模型,从而规范了拖拽事件的处理。
下面结合代码来看看:
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.
仅仅有Drag-Drop模型是不够的,Launcher对系统的Touch event也做了相关的处理.我们知道事件处理的时候一般采用RootView先消费,根据消费结果判断是否分发给ChildView消费的。依次类推,直至到达View的最后一层。onInterceptTouchEvent(MotionEvent)拦截所有的touch事件,经过判断后分发给childview。如果onInterceptTouchEvent返回true,表示事件已经被消费掉了,无需继续转发;如果onInterceptTouchEvent返回false,表示事件需要继续转发给下一层组件.
具体判断的规则如下:
利用Drop& Drag模型的结合Touch Event的处理,配合CellLayout的位置单元格模式的划分,各个组件的拖动,拖入,拖出,摆放都可以轻松的实现了.