系统方向学习总结6 --Launcher3拖拽分析之Workspace


活动地址:CSDN21天学习挑战赛


 最近跟着CSDN大佬,参与一个 21天打卡的活动

 Android framework开发者带你参加21天学习挑战赛活动_安卓兼职framework应用工程师的博客-CSDN博客

Android 10.0 Launcher3 禁止首屏时钟AppWidget拖动到其他屏_安卓兼职framework应用工程师的博客-CSDN博客
 

 先简单分析一下 Workspace#onDragOver()方法 

 分析在Workspace中拖拽item  

DragView存在的意义:代替BubbleTextView,在DragLayer上滑动。为什么呢?因为这个BubbleTextView的父布局不是DragLayer,而我们知道子View滑动是不能超过父view的,所以想想,如果直接让BubbleTextView去滑动,那么它就不能跨布局,因为我们要让这个随手指拖拽的view能随意跨越布局,所以会使用一个可以在整个屏幕上滑动的view,这个就是DragView。那么顺理成章,DragLayer要处理滑动触摸事件。

DragObject:拖拽过程中,最最有权力的类,包含了拖拽所需的一切信息。只要拥有一个DragObject对象,就能获取关于一次拖拽所有的信息。所以你看各种拖拽相关的方法参数中都含有DragObject

Workspace#onDragOver()
 

// 手指在DropTarget中拖拽时候一直调用的方法onDragOver(讨论在Workspace中)

public void onDragOver(DragObject d){
     // 通过DragObject拿到源view的ItemInfo
        ItemInfo item = d.dragInfo;
    
     // 得到dragView中心点坐标,mDragViewVisualCenter是个坐标数组(x,y)
        mDragViewVisualCenter = d.getVisualCenter(mDragViewVisualCenter);
    
      // 拿到源view对象(小部件、文件夹、图标)
        final View child = (mDragInfo == null) ? null : mDragInfo.cell;
    
      // setDropLayoutForDrafObject()返回t表示DragView中心坐标落在了另一个可置放的区域
        if (setDropLayoutForDragObject(d, mDragViewVisualCenter[0], mDragViewVisualCenter[1])) {
            if (mLauncher.isHotseatLayout(mDragTargetLayout)) {
                mSpringLoadedDragController.cancel();
            } else {
                // DragView拽到了下一个可置放的页面,也就是拖到了另一个celllayout(切换页面用了一个计时器)
                mSpringLoadedDragController.setAlarm(mDragTargetLayout);
            }
        }
    
    	// mDragTargetLayout在执行onDropEnter的时候会预先被赋值
    	if(mDragTargetLayout != null){
            
            // 通过CellLayout.fndNearestAree计算出最近的位置坐标,指的是cell的左上角坐标
            mTargetCell = findNearestArea(
                    (int) mDragViewVisualCenter[0],
                    (int) mDragViewVisualCenter[1],
                    minSpanX,
                    minSpanY,
                    mDragTargetLayout,
                    mTargetCell);
            
            // 重新排序后的 X
            int reorderX = mTargetCell[0];
            // 重新排序后的 Y
            int reorderY = mTargetCell[1];

            // 设置当前要放下的左上角坐标,设置拖拽模式为DRAG_MODE_NONE,将mLastReorderX/Y值初始化(均为-1)
            setCurrentDropOverCell(mTargetCell[0], mTargetCell[1]);
            
            // 计算Dragview中心到最近置放区域中心的距离,根据俩点坐标计算距离
            float targetCellDistance = mDragTargetLayout.getDistanceFromCell(
                    mDragViewVisualCenter[0], mDragViewVisualCenter[1], mTargetCell);
            
            // =========== 1 ==============
            // 判断拖拽过程中用户是否是想将一个图标添加到文件夹中还是创建一个新的文件夹
            manageFolderFeedback(targetCellDistance, d);
            
             // 判断最近放置区域是否被占用,Rect相交法
            boolean nearestDropOccupied = mDragTargetLayout.isNearestDropLocationOccupied((int)
                    mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1], item.spanX,
                    item.spanY, child, mTargetCell);
            
              if (!nearestDropOccupied) {
                // 没有被占用,虚拟化最近区域轮廓
                mDragTargetLayout.visualizeDropLocation(d.originalView, mOutlineProvider,
                        mTargetCell[0], mTargetCell[1], item.spanX, item.spanY, false, d);
            } else if ((mDragMode == DRAG_MODE_NONE || mDragMode == DRAG_MODE_REORDER)
                    && !mReorderAlarm.alarmPending() && (mLastReorderX != reorderX ||
                    mLastReorderY != reorderY)) {
                // 这里的else if条件解读:
                // 前俩个是拖拽模式比较简单
                // mReorderAlarm.alarmPending:表示一次排序定时器任务是否挂起,挂起就不能重排序
                // 后面俩个满足其一,也就是和manageFolderFeedBack()方法中的一开始setDragMode联系了
                // 也就是如果上次和当前要排序的位置是一样的,那还排什么序呢,所有必须是某一个不相等才能排序
                int[] resultSpan = new int[2];
                mDragTargetLayout.performReorder((int) mDragViewVisualCenter[0],
                        (int) mDragViewVisualCenter[1], minSpanX, minSpanY, item.spanX, item.spanY,
                        child, mTargetCell, resultSpan, CellLayout.MODE_SHOW_REORDER_HINT);
                  
                // 重排序定时器任务
                ReorderAlarmListener listener = new ReorderAlarmListener(mDragViewVisualCenter,
                        minSpanX, minSpanY, item.spanX, item.spanY, d, child);
                mReorderAlarm.setOnAlarmListener(listener);
                // 执行Workspace#onAlarm()方法重排序
                mReorderAlarm.setAlarm(REORDER_TIMEOUT);
            }

            if (mDragMode == DRAG_MODE_CREATE_FOLDER || mDragMode == DRAG_MODE_ADD_TO_FOLDER ||
                    !nearestDropOccupied) {
                if (mDragTargetLayout != null) {
                    mDragTargetLayout.revertTempState();
                }
            }
            
            
        }
}
 

猜你喜欢

转载自blog.csdn.net/yangbin0513/article/details/126338943