android launcher3拖放功能深入剖析

本文深入剖析Android Launcher3的拖放功能,从长按启动拖放、拖放源与目标处理到拖放结束的过程。通过分析关键代码,揭示了DragController和DropTarget在拖放操作中的作用,以及DragView的创建和移动。
摘要由CSDN通过智能技术生成

Launcherr有一个相对比较复杂的功能就是拖放功能,要深入了解launcher,深入理解拖放功能是有必要的,这篇blog,我将对launcher的拖放功能做深入的了解
1.首先直观感受什么时候开始拖放?我们长按桌面一个应用图标或者控件的时候拖放就开始了,包括在all app view中长按应用图标,下面就是我截取的拖放开始的代码调用堆栈
at com.android.launcher2.DragController.startDrag(DragController.java:170)
at com.android.launcher2.Workspace.startDrag(Workspace.java:1068)
at com.android.launcher2.Launcher.onLongClick(Launcher.java:1683)
at android.view.View.performLongClick(View.java:2427)
at android.widget.TextView.performLongClick(TextView.java:7286)
at android.view.View$CheckForLongPress.run(View.java:8792)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:123)
桌面应用图标由Launcher.onLongClick负责监听处理,插入断点debug进入onLongclick函数
         if (!(v instanceof CellLayout)) {
            v = (View) v.getParent();
        }
                                 //获取桌面CellLayout上一个被拖动的对象
         CellLayout.CellInfo cellInfo = (CellLayout.CellInfo) v.getTag();
               ...
        if (mWorkspace.allowLongPress()) {
            if (cellInfo.cell == null) {
                ...
            } else {
                if (!(cellInfo.cell instanceof Folder)) {
                    ...
                    //调用Workspace.startDrag处理拖动
                    mWorkspace.startDrag(cellInfo);
                }
            }
        }
我上面只写出关键代码,首先是获取被拖动的对象v.getTag(),Tag什么时候被设置进去的了
   public boolean onInterceptTouchEvent(MotionEvent ev) {
        ...
        if (action == MotionEvent.ACTION_DOWN) {
                        ...
            boolean found = false;
            for (int i = count - 1; i >= 0; i--) {
                final View child = getChildAt(i);

                if ((child.getVisibility()) == VISIBLE || child.getAnimation() != null) {
                    child.getHitRect(frame);
                    //判断区域是否在这个子控件的区间,如果有把child信息赋给mCellInfo
                    if (frame.contains(x, y)) {
                        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
                        cellInfo.cell = child;
                        cellInfo.cellX = lp.cellX;
                        cellInfo.cellY = lp.cellY;
                        cellInfo.spanX = lp.cellHSpan;
                        cellInfo.spanY = lp.cellVSpan;
                        cellInfo.valid = true;
                        found = true;
                        mDirtyTag = false;
                        break;
                    }
                }
            }
            
            mLastDownOnOccupiedCell = found;

            if (!found) {
                            ...
                            //没有child view 说明没有点击桌面图标项
                cellInfo.cell = null;                
            }
            setTag(cellInfo);
        }
看了上面代码知道,当开始点击桌面时,celllayout就会根据点击区域去查找在该区域是否有child存在,若有把它设置为tag.cell,没有,tag.cell设置为null,后面在开始拖放时launcher.onlongclick中对tag进行处理,
这个理顺了,再深入到workspace.startDrag函数,workspace.startDrag调用DragController.startDrag去处理拖放
mDragController.startDrag(child, this, child.getTag(), DragController.DRAG_ACTION_MOVE);
再分析一下上面调用的几个参数
child = tag.cell
this = workspace
child.getTag()是什么呢?在什么时候被设置?再仔细回顾原来launcher加载过程代码,在launcher.createShortcut中它被设置了:注意下面我代码中的注释
    View createShortcut(int layoutResId, ViewGroup parent, ShortcutInfo info) {
        TextView favorite = (TextView) mInflater.inflate(layoutResId, parent, false);

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值