Android13-Launcer3_桌面-长按图标添加抖动动画

248 阅读2分钟

长按事件分析

WorkspaceLayoutManager

    default void addInScreen(View child, int container, int screenId, int x, int y,
            int spanX, int spanY) {
        if (container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
            if (getScreenWithId(screenId) == null) {
                Log.e(TAG, "Skipping child, screenId " + screenId + " not found");
                // DEBUGGING - Print out the stack trace to see where we are adding from
                new Throwable().printStackTrace();
                return;
            }
        }
        if (EXTRA_EMPTY_SCREEN_IDS.contains(screenId)) {
            // This should never happen
            throw new RuntimeException("Screen id should not be extra empty screen: " + screenId);
        }

        final CellLayout layout;
        if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT
                || container == LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION) {
            layout = getHotseat();

            // Hide folder title in the hotseat
            if (child instanceof FolderIcon) {
                ((FolderIcon) child).setTextVisible(false);
            }
        } else {
            // Show folder title if not in the hotseat
            if (child instanceof FolderIcon) {
                ((FolderIcon) child).setTextVisible(true);
            }
            layout = getScreenWithId(screenId);
        }

        ViewGroup.LayoutParams genericLp = child.getLayoutParams();
        CellLayoutLayoutParams lp;
        if (genericLp == null || !(genericLp instanceof CellLayoutLayoutParams)) {
            lp = new CellLayoutLayoutParams(x, y, spanX, spanY, screenId);
        } else {
            lp = (CellLayoutLayoutParams) genericLp;
            lp.cellX = x;
            lp.cellY = y;
            lp.cellHSpan = spanX;
            lp.cellVSpan = spanY;
        }

        if (spanX < 0 && spanY < 0) {
            lp.isLockedToGrid = false;
        }

        // Get the canonical child id to uniquely represent this view in this screen
        ItemInfo info = (ItemInfo) child.getTag();
        int childId = info.getViewId();

        boolean markCellsAsOccupied = !(child instanceof Folder);
        if (!layout.addViewToCellLayout(child, -1, childId, lp, markCellsAsOccupied)) {
            // TODO: This branch occurs when the workspace is adding views
            // outside of the defined grid
            // maybe we should be deleting these items from the LauncherModel?
            Log.e(TAG, "Failed to add to item at (" + lp.cellX + "," + lp.cellY + ") to CellLayout");
        }

        child.setHapticFeedbackEnabled(false);
        //这里添加长按事件
        child.setOnLongClickListener(getWorkspaceChildOnLongClickListener());
        if (child instanceof DropTarget) {
            onAddDropTarget((DropTarget) child);
        }
    }
    
    default View.OnLongClickListener getWorkspaceChildOnLongClickListener() {
        return ItemLongClickListener.INSTANCE_WORKSPACE;
    }

这里给View添加一个动画效果

    private static boolean onWorkspaceItemLongClick(View v) {
        if (v instanceof LauncherAppWidgetHostView) {
            TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "Widgets.onLongClick");
        } else {
            TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onWorkspaceItemLongClick");
        }
        //添加抖动动画
        addCusShakeAnimate(v);

        Launcher launcher = Launcher.getLauncher(v.getContext());
        if (!canStartDrag(launcher)) return false;
        if (!launcher.isInState(NORMAL) && !launcher.isInState(OVERVIEW)) return false;
        if (!(v.getTag() instanceof ItemInfo)) return false;

        launcher.setWaitingForResult(null);
        beginDrag(v, launcher, (ItemInfo) v.getTag(), launcher.getDefaultWorkspaceDragOptions());
        return true;
    }

    private static void addCusShakeAnimate(View view) {
        TranslateAnimation leftBottomTranslate = new TranslateAnimation(0, -20, 0, -20);
        leftBottomTranslate.setDuration(200);
        leftBottomTranslate.setRepeatCount(3);
        leftBottomTranslate.setRepeatMode(Animation.REVERSE);
        TranslateAnimation leftTopTranslate = new TranslateAnimation(0, -20, 0, 20);
        leftTopTranslate.setDuration(200);
        leftTopTranslate.setRepeatCount(3);
        leftTopTranslate.setRepeatMode(Animation.REVERSE);
        TranslateAnimation rightTopTranslate = new TranslateAnimation(0, 20, 0, 20);
        rightTopTranslate.setDuration(200);
        rightTopTranslate.setRepeatCount(3);
        rightTopTranslate.setRepeatMode(Animation.REVERSE);

        AnimationSet shakeAnimationSet = new AnimationSet(false);
        shakeAnimationSet.addAnimation(leftBottomTranslate);
        view.setAnimation(shakeAnimationSet);
        leftBottomTranslate.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                view.startAnimation(leftTopTranslate);
            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });
        leftTopTranslate.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                view.startAnimation(rightTopTranslate);
            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });
        rightTopTranslate.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                view.startAnimation(leftBottomTranslate);
            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });
        view.startAnimation(shakeAnimationSet);
    }
    public static void beginDrag(View v, Launcher launcher, ItemInfo info,
            DragOptions dragOptions) {
        if (info.container >= 0) {
            Folder folder = Folder.getOpen(launcher);
            if (folder != null) {
                if (!folder.getIconsInReadingOrder().contains(v)) {
                    folder.close(true);
                } else {
                    folder.startDrag(v, dragOptions);
                    return;
                }
            }
        }

        //把当前抖动的View赋值给DragController,开始移动的时候清除动画
        DragController dragController = launcher.getDragController();
        dragController.setCurShakeView(v);

        CellLayout.CellInfo longClickCellInfo = new CellLayout.CellInfo(v, info);
        launcher.getWorkspace().startDrag(longClickCellInfo, dragOptions);
    }

beginDrag()方法通过startDrag()方法一直调用到DragController的startDrag()方法

DragController是一个抽象类,Launcher这里初始化的是LauncherDragController 类

public abstract class DragController<T extends ActivityContext>
        implements DragDriver.EventListener, TouchController {
public class LauncherDragController extends DragController<Launcher> {

Laucher

    protected void initDragController() {
        mDragController = new LauncherDragController(this);
    }

LauncherDragController 的startDrag()会调用到handleMoveEvent()方法,这里处理移动时清除动画

    
	  private View mCurShakeView;
    private int mLastDragX = -1;
    private int mLastDragY = -1;
    
    protected void handleMoveEvent(int x, int y) {
        mDragObject.dragView.move(x, y);
        //一有移动清除动画
        if(mLastDragX != -1 && mLastDragY != -1){
            if(Math.abs(mLastDragX - x) > 10 ||  Math.abs(mLastDragY - y) > 10){
                if(null != mCurShakeView){
                    mCurShakeView.clearAnimation();
                }
            }
        }
        mLastDragX = x;
        mLastDragY = 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.hypot(mLastTouch.x - x, mLastTouch.y - y);
        mLastTouch.set(x, y);

        int distanceDragged = mDistanceSinceScroll;
        if (ATLEAST_Q && mLastTouchClassification == MotionEvent.CLASSIFICATION_DEEP_PRESS) {
            distanceDragged /= DEEP_PRESS_DISTANCE_FACTOR;
        }
        if (mIsInPreDrag && mOptions.preDragCondition != null
                && mOptions.preDragCondition.shouldStartDrag(distanceDragged)) {
            callOnDragStart();
        }
    }

效果
抖动动画.gif