Launcher 拖拽分析

前言

image.png
在手机屏幕上通过长按动作可以对图标拖拽删除,我们有了多个问题:

  1. Android 是怎样找到我们所长按的那个图标的?
  2. 进行拖拽伴随着图标的震动和动画是怎样实现的?

分析代码

我们知道长按屏幕是在 WorkSpace 进行操作的,所以我们直接在这个类中处理长按的方法。

@Override
    public void performLongClick(final float motionX, final float motionY) {
         // 非滑动状态且找到了对应的 cell
        Log.i("检测长按",findTouchCellInfo(motionX, motionY)+" ");
        if (!mDraging && findTouchCellInfo(motionX, motionY)) {
            //添加一屏
            addCellLayout();
            //遍历所有 CellLayout 启动动画
            startChildShakeAnim();
            //找到点击位置所在的 cellInfo
            findDragTouchCellInfo(motionX, motionY);

            //Toast.makeText(getContext(),"长按",Toast.LENGTH_SHORT).show();
        }
    }

其中 findDragTouchCellInfo(motionX, motionY) 处理了拖拽图标找到点击位置所在的 cellInfo,我们继续追踪。

在该方法中对应用图标和文件夹分类处理,调用 startDraw () 开始处理拖拽,

image.png

在DragController中,startDrag是个多态方法,但最终,都走到了以下这个实现中。

public void startDrag(Bitmap b, int dragLayerX, int dragLayerY, DragSource source, Object dragInfo, int dragAction, Point dragOffset, Rect dragRegion) 

handleMoveEvent 是拖拽的主要方法,当用户触发拖拽后,DragController将通过该方法移动被拖拽物视图,并通知各个释放目的对象相应状态的改变。若进入滑屏区域且允许滑屏,执行相应的滑屏操作。

DragController 拖拽控制流程总结

  • 方法流程:(Launcher.onLongClick()-Workspace.beginDragShared()/AppsCustomizePagedView.beginDragging() -> )startDrag() -> onInterceptTouchEvent()/onTouchEvent() -> handleMoveEvent() -> drop()

  • 总的来说,DragController 拖拽控制就是(在进入拖拽之前的步骤见2触发拖拽):

    1. 进入拖拽:使用 startDrag() 进入拖拽状态;
    2. 响应触屏:使用 onInterceptTouchEvent() 与 onTouchEvent() 响应用户的触屏动作;
    3. 处理拖拽:使用 handleMoveEvent() 处理被拖拽物的移动;
    4. 释放拖拽:使用 drop() 将被拖拽物释放到相应位置。

Android 是怎样找到我们长按的那个图标的?

坐标,在 WorkSpace 中可以找到 findDragTouchCellInfo 方法 , 这个方法将长按处理分成两类,一类是 HotSeat ,另一类是 CellLayout 。

使用 setTagToCellInfoForPoint(x,y)遍历查找坐标所对应的元素

/**
     * 设置点击目标TAG 查找X,Y是否在那个目标上
     * 
     * @param touchX
     * @param touchY
     */
    public boolean setTagToCellInfoForPoint(int touchX, int touchY) {
        final CellInfo cellInfo = mCellInfo;
        Rect frame = mRect;
        final int x = touchX + getScrollX();
        final int y = touchY + getScrollY();
        final int count = mChildren.getChildCount();

        boolean found = false;
        for (int i = count - 1; i >= 0; i--) {
            final View child = mChildren.getChildAt(i);
            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
            if ((child.getVisibility() == VISIBLE || child.getAnimation() != null)) {
                child.getHitRect(frame);
                if (getParent() instanceof HotSeat) { // 这里解决hotseat里长按图标无响应的问题
                    frame.offset(mOffsetX, getPaddingTop());
                } else if (getParent() instanceof Workspace) { // 只有workspace里面的celllayout事件是基于DragLayer
                    frame.offset(getPaddingLeft(), getPaddingTop() + LauncherModel.getScreenOffset());
                } else if (getParent() instanceof FolderLayout) {
                    frame.offset(getPaddingLeft(), getPaddingTop());
                }

                // 判断 framne 中是否有对应的坐标
                if (frame.contains(x, y)) {
                    cellInfo.view = child;
                    cellInfo.cellX = lp.cellX;
                    cellInfo.cellY = lp.cellY;
                    cellInfo.cellHSpan = lp.cellHSpan;
                    cellInfo.cellVSpan = lp.cellVSpan;
                    //已经找到了,跳出循环
                    found = true;
                    break;
                }
            }
        }
        mLastDownOnOccupiedCell = found;

        if (!found) {
            final int cellXY[] = mTmpXY;
            pointToCellExact(x, y, cellXY);

            cellInfo.view = null;
            cellInfo.cellX = cellXY[0];
            cellInfo.cellY = cellXY[1];
            cellInfo.cellHSpan = 1;
            cellInfo.cellVSpan = 1;
        }
        setTag(cellInfo);
        return found;
    }

进行拖拽伴随着图标的震动和动画是怎样实现的?

刚开始以为在 DragView 的属性动画里实现,后面回过头才发现就在 WorkSpace 中调用 startChildShakeAnim(),实现桌面图标抖动。

public void startChildShakeAnim() {
        for (int i = 0; i < getChildCount(); i++) {
            if (getChildAt(i) instanceof CellLayout && getChildAt(i).getVisibility() != View.GONE) {
                ((CellLayout) getChildAt(i)).startChildDelAnim();
            }
        }

        if (mLauncher.getHotSeat().getChildCount() > 0)
            ((CellLayout) mLauncher.getHotSeat().getChildAt(0)).startChildDelAnim();
        mDraging = true;
        setAllowVerticalScroll(false);
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
仿Launcher的GridView动是一个长按GridView的item,然后将其其他item上面,使得GridView的item发生交换,比较典型的就是我们的Launcher,网上有很多关于GridView的动的Demo,但是大部分都是相同的,而且存在一些Bug,而且大部分都是点击GridView的item然后进行动,或者item之间不进行实时交换,今天给大家更加详细的介绍GridView,并且将Demo做的更完美。   实现思路: 1、根据手指按下的X,Y坐标来获取我们在GridView上面点击的item 2、手指按下的时候使用Handler和Runnable来实现一个定时器,假如定时时间为1000毫秒,在1000毫秒内,如果手指抬起了移除定时器,没有抬起并且手指点击在GridView的item所在的区域,则表示我们长按了GridView的item 3、如果我们长按了item则隐藏item,然后使用WindowManager来添加一个item的镜像在屏幕用来代替刚刚隐藏的item 4、当我们手指在屏幕移动的时候,更新item镜像的位置,然后在根据我们移动的X,Y的坐标来获取移动到GridView的哪一个位置 5、到GridView的item过多的时候,可能一屏幕显示不完,我们手指动item镜像到屏幕下方,要触发GridView想上滚动,同理,当我们手指动item镜像到屏幕上面,触发GridView向下滚动 6、GridView交换数据,刷新界面,移除item的镜像 本例子来自于CSND xiaanming的博客,详细的源码分析已经帮大家离线成pdf文档了。   

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值