• launcher5.0-拖动讲解


    图标拖动过程先长按,拖动,松开手指

    launcher.java中setupViews方法,

     private void setupViews() {
            final DragController dragController = mDragController;
    
            mLauncherView = findViewById(R.id.launcher);
            mDragLayer = (DragLayer) findViewById(R.id.drag_layer);
            mWorkspace = (Workspace) mDragLayer.findViewById(R.id.workspace);
            mQsbDivider = findViewById(R.id.qsb_divider);
            mDockDivider = findViewById(R.id.dock_divider);
    
            mLauncherView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
            mWorkspaceBackgroundDrawable = getResources().getDrawable(R.drawable.workspace_bg);
    
            // Setup the drag layer
            mDragLayer.setup(this, dragController);
    
            // Setup the hotseat
            mHotseat = (Hotseat) findViewById(R.id.hotseat);
            if (mHotseat != null) {
                mHotseat.setup(this);
            }
    
            // Setup the workspace
            mWorkspace.setHapticFeedbackEnabled(false);
            mWorkspace.setOnLongClickListener(this);
            mWorkspace.setup(dragController);
            dragController.addDragListener(mWorkspace);
    
            // Get the search/delete bar
            mSearchDropTargetBar = (SearchDropTargetBar) mDragLayer.findViewById(R.id.qsb_bar);
    
            // Setup AppsCustomize
            mAppsCustomizeTabHost = (AppsCustomizeTabHost) findViewById(R.id.apps_customize_pane);
            mAppsCustomizeContent = (AppsCustomizePagedView)
                    mAppsCustomizeTabHost.findViewById(R.id.apps_customize_pane_content);
            mAppsCustomizeContent.setup(this, dragController);
    
            // Setup the drag controller (drop targets have to be added in reverse order in priority)
            dragController.setDragScoller(mWorkspace);
            dragController.setScrollView(mDragLayer);
            dragController.setMoveTarget(mWorkspace);
            dragController.addDropTarget(mWorkspace);
            if (mSearchDropTargetBar != null) {
                mSearchDropTargetBar.setup(this, dragController);
            }
        }
     mWorkspace.setOnLongClickListener(this); 看 onLongClick 方法

      public boolean onLongClick(View v) {
            if (!isDraggingEnabled()) return false;
            if (isWorkspaceLocked()) return false;
            if (mState != State.WORKSPACE) return false;
    
            if (!(v instanceof CellLayout)) {
                v = (View) v.getParent().getParent();
            }
    
            resetAddInfo();
            CellLayout.CellInfo longClickCellInfo = (CellLayout.CellInfo) v.getTag();
            // This happens when long clicking an item with the dpad/trackball
            if (longClickCellInfo == null) {
                return true;
            }
    
            // The hotseat touch handling does not go through Workspace, and we always allow long press
            // on hotseat items.
            final View itemUnderLongClick = longClickCellInfo.cell;
            boolean allowLongPress = isHotseatLayout(v) || mWorkspace.allowLongPress();
            if (allowLongPress && !mDragController.isDragging()) {
                if (itemUnderLongClick == null) {
                    // User long pressed on empty space
                    mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
                            HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
                    startWallpaper();
                } else {
                    if (!(itemUnderLongClick instanceof Folder)) {
                        // User long pressed on an item
                        mWorkspace.startDrag(longClickCellInfo);
                    }
                }
            }
            return true;
        }

    如上:longClickCellInfo 在哪个cell中长按(桌面page或者hotseatlayout) ,itemUnderLongClick 是 被长按的view

    如果 itemUnderLongClick 为空则长按空白区域 则执行startWallpaper()换壁纸,如果为非文件夹item(如app或者快捷方式)则执行

     mWorkspace.startDrag(longClickCellInfo) 拖拽。

    void startDrag(CellLayout.CellInfo cellInfo) {
            View child = cellInfo.cell;
    
            // Make sure the drag was started by a long press as opposed to a long click.
            if (!child.isInTouchMode()) {
                return;
            }
    
            mDragInfo = cellInfo;
            child.setVisibility(INVISIBLE);
            CellLayout layout = (CellLayout) child.getParent().getParent();
            layout.prepareChildForDrag(child);
    
            child.clearFocus();
            child.setPressed(false);
    
            final Canvas canvas = new Canvas();
    
            // The outline is used to visualize where the item will land if dropped
            mDragOutline = createDragOutline(child, canvas, DRAG_BITMAP_PADDING);
            beginDragShared(child, this);
        }
    createDragOutline(child, canvas, DRAG_BITMAP_PADDING) 长按后创建移动的投影边框
    beginDragShared(child, this)开始拖拽移动

    public void beginDragShared(View child, DragSource source) {
            Resources r = getResources();
    
            // The drag bitmap follows the touch point around on the screen
            final Bitmap b = createDragBitmap(child, new Canvas(), DRAG_BITMAP_PADDING);
    
            final int bmpWidth = b.getWidth();
            final int bmpHeight = b.getHeight();
    
            float scale = mLauncher.getDragLayer().getLocationInDragLayer(child, mTempXY);
            int dragLayerX =
                    Math.round(mTempXY[0] - (bmpWidth - scale * child.getWidth()) / 2);
            int dragLayerY =
                    Math.round(mTempXY[1] - (bmpHeight - scale * bmpHeight) / 2
                            - DRAG_BITMAP_PADDING / 2);
    
            Point dragVisualizeOffset = null;
            Rect dragRect = null;
            if (child instanceof BubbleTextView || child instanceof PagedViewIcon) {
                int iconSize = r.getDimensionPixelSize(R.dimen.app_icon_size);
                int iconPaddingTop = r.getDimensionPixelSize(R.dimen.app_icon_padding_top);
                int top = child.getPaddingTop();
                int left = (bmpWidth - iconSize) / 2;
                int right = left + iconSize;
                int bottom = top + iconSize;
                dragLayerY += top;
                // Note: The drag region is used to calculate drag layer offsets, but the
                // dragVisualizeOffset in addition to the dragRect (the size) to position the outline.
                dragVisualizeOffset = new Point(-DRAG_BITMAP_PADDING / 2,
                        iconPaddingTop - DRAG_BITMAP_PADDING / 2);
                dragRect = new Rect(left, top, right, bottom);
            } else if (child instanceof FolderIcon) {
                int previewSize = r.getDimensionPixelSize(R.dimen.folder_preview_size);
                dragRect = new Rect(0, 0, child.getWidth(), previewSize);
            }
    
            // Clear the pressed state if necessary
            if (child instanceof BubbleTextView) {
                BubbleTextView icon = (BubbleTextView) child;
                icon.clearPressedOrFocusedBackground();
            }
    
            mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(),
                    DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect, scale);
            b.recycle();
    
            // Show the scrolling indicator when you pick up an item
            showScrollingIndicator(false);
        }

    final Bitmap b = createDragBitmap(child, new Canvas(), DRAG_BITMAP_PADDING);创建了图标图片

     float scale = mLauncher.getDragLayer().getLocationInDragLayer(child, mTempXY);获取scale图标缩放比和mTempXY所方比后的左上角坐标

    dragLayerX,dragLayerY 拖动图标的显示位置
    执行

    mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(),DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect, scale);
    交给
    mDragController.startDrag去执行拖动
    public void startDrag(Bitmap b, int dragLayerX, int dragLayerY,
                DragSource source, Object dragInfo, int dragAction, Point dragOffset, Rect dragRegion,
                float initialDragViewScale) {
            if (PROFILE_DRAWING_DURING_DRAG) {
                android.os.Debug.startMethodTracing("Launcher");
            }
    
            // Hide soft keyboard, if visible
            if (mInputMethodManager == null) {
                mInputMethodManager = (InputMethodManager)
                        mLauncher.getSystemService(Context.INPUT_METHOD_SERVICE);
            }
            mInputMethodManager.hideSoftInputFromWindow(mWindowToken, 0);
    
            for (DragListener listener : mListeners) {
                listener.onDragStart(source, dragInfo, dragAction);
            }
    
            final int registrationX = mMotionDownX - dragLayerX;
            final int registrationY = mMotionDownY - dragLayerY;
    
            final int dragRegionLeft = dragRegion == null ? 0 : dragRegion.left;
            final int dragRegionTop = dragRegion == null ? 0 : dragRegion.top;
    
            mDragging = true;
    
            mDragObject = new DropTarget.DragObject();
    
            mDragObject.dragComplete = false;
            mDragObject.xOffset = mMotionDownX - (dragLayerX + dragRegionLeft);
            mDragObject.yOffset = mMotionDownY - (dragLayerY + dragRegionTop);
            mDragObject.dragSource = source;
            mDragObject.dragInfo = dragInfo;
    
            mVibrator.vibrate(VIBRATE_DURATION);
    
            final DragView dragView = mDragObject.dragView = new DragView(mLauncher, b, registrationX,
                    registrationY, 0, 0, b.getWidth(), b.getHeight(), initialDragViewScale);
    
            if (dragOffset != null) {
                dragView.setDragVisualizeOffset(new Point(dragOffset));
            }
            if (dragRegion != null) {
                dragView.setDragRegion(new Rect(dragRegion));
            }
    
            dragView.show(mMotionDownX, mMotionDownY);
            handleMoveEvent(mMotionDownX, mMotionDownY);
        }

    生成当前的拖动mDragObject对象 含有拖动信息 如dragInfo 坐标信息

    mMotionDownX,mMotionDownY 手指按下的坐标

     dragView.show(mMotionDownX, mMotionDownY) 显示拖动view

     其他 图标移位,图标晃动等交给  handleMoveEvent(mMotionDownX, mMotionDownY)处理 ,handleMoveEvent在onTouchEvent中也有调用,拖动中不断调用

    public boolean onTouchEvent(MotionEvent ev) {
            if (!mDragging) {
                return false;
            }
    
            // Update the velocity tracker
            acquireVelocityTrackerAndAddMovement(ev);
    
            final int action = ev.getAction();
            final int[] dragLayerPos = getClampedDragLayerPos(ev.getX(), ev.getY());
            final int dragLayerX = dragLayerPos[0];
            final int dragLayerY = dragLayerPos[1];
    
            switch (action) {
            case MotionEvent.ACTION_DOWN:
                // Remember where the motion event started
                mMotionDownX = dragLayerX;
                mMotionDownY = dragLayerY;
    
                if ((dragLayerX < mScrollZone) || (dragLayerX > mScrollView.getWidth() - mScrollZone)) {
                    mScrollState = SCROLL_WAITING_IN_ZONE;
                    mHandler.postDelayed(mScrollRunnable, SCROLL_DELAY);
                } else {
                    mScrollState = SCROLL_OUTSIDE_ZONE;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                handleMoveEvent(dragLayerX, dragLayerY);

    看下方法 handleMoveEvent

    private void handleMoveEvent(int x, int y) {
            mDragObject.dragView.move(x, y);
    
            // Drop on someone?
            final int[] coordinates = mCoordinatesTemp;
            DropTarget dropTarget = findDropTarget(x, y, coordinates);
            mDragObject.x = coordinates[0];
            mDragObject.y = coordinates[1];
            checkTouchMove(dropTarget);
    
            // Check if we are hovering over the scroll areas
            mDistanceSinceScroll +=
                Math.sqrt(Math.pow(mLastTouch[0] - x, 2) + Math.pow(mLastTouch[1] - y, 2));
            mLastTouch[0] = x;
            mLastTouch[1] = y;
            checkScrollState(x, y);
        }

    先分析DropTarget类  

    public interface DropTarget {
    
       ...

    void onDrop(DragObject dragObject); void onDragEnter(DragObject dragObject); void onDragOver(DragObject dragObject); void onDragExit(DragObject dragObject); ... }
    • onDragEnter是当拖动图标到某一DropTarget(蓝色),边缘,刚刚进入DropTarget范围内的时候所调用的内容。比如说我们拖动桌面的一个快捷方式,到桌面顶端的删除区域,“删除”两字和手中的图标会变红,这些动作都是在onDragEnter回调中完成的
    • onDragOver是在某一DropTarget内部移动的时候会调用的回调,比如我们把手上的图标移动到两个图标中间的时候,会发生挤位的情况(就是桌面已有图标让出空位),基本上每个ACTION_MOVE操作都会调用他。
    • onDragExit是从某一DropTarget拖出时候会进行的回调,比如onDragEnter时变红的“删除”和图标会在这个调用中恢复正常。
    • onDrop是松手时候发生的调用,做一些放下时候的操作,比如删除快捷方式的时候会在onDrop里面开始删除的操作。

    右键 open Type Hierchy 显示 继承DropTarget 三个类 分别是 ButtonDropTarge(长按后显示的删除区域)  Folder(文件夹) Workspace (桌面区域)

    接着分析handleMoveEvent

    int x, int y 是当前手指拖动坐标

    DropTarget dropTarget = findDropTarget(x, y, coordinates); 表示拖动到删除区域,文件夹还是在左面工作区

     checkTouchMove(dropTarget);函数

     private void checkTouchMove(DropTarget dropTarget) {
            if (dropTarget != null) {
                DropTarget delegate = dropTarget.getDropTargetDelegate(mDragObject);
                if (delegate != null) {
                    dropTarget = delegate;
                }
    
                if (mLastDropTarget != dropTarget) {
                    if (mLastDropTarget != null) {
                        mLastDropTarget.onDragExit(mDragObject);
                    }
                    dropTarget.onDragEnter(mDragObject);
                }
                dropTarget.onDragOver(mDragObject);
            } else {
                if (mLastDropTarget != null) {
                    mLastDropTarget.onDragExit(mDragObject);
                }
            }
            mLastDropTarget = dropTarget;
        }

    设置各种效果 具体在DropTarget实现类中

    checkScrollState 检查是否拖动到桌面边缘 触法Scroll效果

    这就是拖动过程 接下来看手指松开代码 DragControler onTouchEvent

         case MotionEvent.ACTION_UP:
                // Ensure that we've processed a move event at the current pointer location.
                handleMoveEvent(dragLayerX, dragLayerY);
                mHandler.removeCallbacks(mScrollRunnable);
    
                if (mDragging) {
                    PointF vec = isFlingingToDelete(mDragObject.dragSource);
                    if (vec != null) {
                        dropOnFlingToDeleteTarget(dragLayerX, dragLayerY, vec);
                    } else {
                        drop(dragLayerX, dragLayerY);
                    }
                }
                endDrag();
                break;
     PointF vec = isFlingingToDelete(mDragObject.dragSource);是否是删除图标
    删除图标执行
    dropOnFlingToDeleteTarget(dragLayerX, dragLayerY, vec);
    否则执行drop(dragLayerX, dragLayerY);
  • 相关阅读:
    activiti 任务节点 处理人设置【转】
    activiti 中的签收与委托 操作
    [转] shiro简单配置
    Angular-ui/bootstarp modal 主控制器与模态框控制器传值
    angular之$on、$emit、$broadcast
    AngularJs动态添加元素和删除元素
    angular.element
    angularJs的工具方法
    AngularJS $watch 监听
    AngularJs 延时器、计时器
  • 原文地址:https://www.cnblogs.com/wjw334/p/4314167.html
Copyright © 2020-2023  润新知