Launcher三方应用界面手势

16 篇文章 0 订阅
7 篇文章 0 订阅

问题背景

客户在低配置机器上,原生的三方应用界面上滑home动画负载太重,动画效果卡顿。
希望去掉上滑跟手效果、修改上滑回home动画为最简单的透明度和缩放。

https://blog.csdn.net/a396604593/article/details/129733464中介绍了一些手势的知识

之前有关于这部分的简单逻辑 https://blog.csdn.net/a396604593/article/details/123487805参考第11条
以此为前提,进一步对launcher手势部分加深了一点了解,供各位参考

实现方案

1、屏蔽三方应用界面跟手效果
只屏蔽上下跟手,左右快速切换应用跟手保留
2、上滑回home动画修改,recent和其它动画保留,home动画时间调整

相关流程

本篇文章基于Android R,最新的代码大同小异,可以参考流程。
主要介绍Launcher的三方应用界面上滑、左右滑动切换Task功能。调用逻辑和一些控制判断

1、OtherActivityInputConsumer.onMotionEvent

相关的流程主要在DOWN、MOVE、UP中

1.0、 ACTION_DOWN
case ACTION_DOWN: {
    Object traceToken = TraceHelper.INSTANCE.beginSection(DOWN_EVT,
            FLAG_CHECK_FOR_RACE_CONDITIONS);
    mActivePointerId = ev.getPointerId(0);
    mDownPos.set(ev.getX(), ev.getY());//记录坐标
    mLastPos.set(mDownPos);//记录坐标

    // Start the window animation on down to give more time for launcher to draw if the
    // user didn't start the gesture over the back button
    if (!mIsDeferredDownTarget) {
    	//启动触摸跟手动画前期工作
        startTouchTrackingForWindowAnimation(ev.getEventTime());
    }

    TraceHelper.INSTANCE.endSection(traceToken);
    break;
}
1.1、startTouchTrackingForWindowAnimation中
    private void startTouchTrackingForWindowAnimation(long touchTimeMs) {
        ActiveGestureLog.INSTANCE.addLog("startRecentsAnimation");

        mInteractionHandler = mHandlerFactory.newHandler(mGestureState, touchTimeMs,
                mTaskAnimationManager.isRecentsAnimationRunning());//上滑handler初始化
        mInteractionHandler.setGestureEndCallback(this::onInteractionGestureFinished);
        //初始化运动检测器,用于判断滑动是否停顿
        mMotionPauseDetector.setOnMotionPauseListener(mInteractionHandler::onMotionPauseChanged);
        Intent intent = new Intent(mInteractionHandler.getLaunchIntent());
        mInteractionHandler.initWhenReady(intent);//上滑handler初始化

        if (mTaskAnimationManager.isRecentsAnimationRunning()) {
            mActiveCallbacks = mTaskAnimationManager.continueRecentsAnimation(mGestureState);
            mActiveCallbacks.addListener(mInteractionHandler);
            mTaskAnimationManager.notifyRecentsAnimationState(mInteractionHandler);
            notifyGestureStarted(true /*isLikelyToStartNewTask*/);
        } else {
            intent.putExtra(INTENT_EXTRA_LOG_TRACE_ID, mGestureState.getGestureId());
            //启动home动画的前提
            mActiveCallbacks = mTaskAnimationManager.startRecentsAnimation(mGestureState, intent,
                    mInteractionHandler);
        }
    }

startRecentsAnimation,最终走到startRecentsActivity。达到的效果就是launcher生命周期走到onStart,launcher启动了但是没有完全进入launcher。

1.3、ACTION_MOVE
    case ACTION_MOVE: {
        int pointerIndex = ev.findPointerIndex(mActivePointerId);
        if (pointerIndex == INVALID_POINTER_ID) {
            break;
        }
        mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex));//更新当前点的坐标
        float displacement = getDisplacement(ev);//计算偏移
        float displacementX = mLastPos.x - mDownPos.x;//x偏移
        float displacementY = mLastPos.y - mDownPos.y;//Y偏移

        if (!mPassedWindowMoveSlop) {
            if (!mIsDeferredDownTarget) {
                // Normal gesture, ensure we pass the drag slop before we start tracking
                // the gesture
                if (Math.abs(displacement) > mTouchSlop) {//如果移动大于mTouchSlop,认为开始滑动
                    mPassedWindowMoveSlop = true;
                    mStartDisplacement = Math.min(displacement, -mTouchSlop);
                }
            }
        }

        float horizontalDist = Math.abs(displacementX);//x方向移动的距离
        float upDist = -displacement;//上滑距离
        boolean passedSlop = squaredHypot(displacementX, displacementY)
                >= mSquaredTouchSlop;
        if (!mPassedSlopOnThisGesture && passedSlop) {
            mPassedSlopOnThisGesture = true;
        }
        // Until passing slop, we don't know what direction we're going, so assume
        // we're quick switching to avoid translating recents away when continuing
        // the gesture (in which case mPassedPilferInputSlop starts as true).
        boolean haveNotPassedSlopOnContinuedGesture =
                !mPassedSlopOnThisGesture && mPassedPilferInputSlop;
        boolean isLikelyToStartNewTask = haveNotPassedSlopOnContinuedGesture
                || horizontalDist > upDist;//区分是左右滑动还是上下滑动

        if (!mPassedPilferInputSlop) {
            if (passedSlop) {
                if (mDisableHorizontalSwipe
                        && Math.abs(displacementX) > Math.abs(displacementY)) {
                    // Horizontal gesture is not allowed in this region
                    forceCancelGesture(ev);
                    break;
                }

                mPassedPilferInputSlop = true;

                if (mIsDeferredDownTarget) {
                    // Deferred gesture, start the animation and gesture tracking once
                    // we pass the actual touch slop
                    startTouchTrackingForWindowAnimation(ev.getEventTime());
                }
                if (!mPassedWindowMoveSlop) {
                    mPassedWindowMoveSlop = true;
                    mStartDisplacement = Math.min(displacement, -mTouchSlop);

                }
                notifyGestureStarted(isLikelyToStartNewTask);
            }
        }

        if (mInteractionHandler != null) {
            if (mPassedWindowMoveSlop) {
                // Move
                //上下滑动更新移动位置
                mInteractionHandler.updateDisplacement(displacement - mStartDisplacement);
            }

            if (mDeviceState.isFullyGesturalNavMode()) {
                mMotionPauseDetector.setDisallowPause(upDist < mMotionPauseMinDisplacement
                        || isLikelyToStartNewTask);
                mMotionPauseDetector.addPosition(ev);
                mInteractionHandler.setIsLikelyToStartNewTask(isLikelyToStartNewTask);
            }
        }
        break;
    }
1.4、ACTION_UP
    case ACTION_CANCEL:
    case ACTION_UP: {
        if (DEBUG_FAILED_QUICKSWITCH && !mPassedWindowMoveSlop) {
            float displacementX = mLastPos.x - mDownPos.x;
            float displacementY = mLastPos.y - mDownPos.y;
            Log.d("Quickswitch", "mPassedWindowMoveSlop=false"
                    + " disp=" + squaredHypot(displacementX, displacementY)
                    + " slop=" + mSquaredTouchSlop);
        }
        //up或者cancel之后,处理后续界面走向
        finishTouchTracking(ev);
1.5、finishTouchTracking

松手后进入home或者recent以及动画处理
后续我们只关注home的相关逻辑和动画,其它的逻辑暂时忽略

    private void finishTouchTracking(MotionEvent ev) {
    	...
            if (mPassedWindowMoveSlop && mInteractionHandler != null) {
            if (ev.getActionMasked() == ACTION_CANCEL) {
                mInteractionHandler.onGestureCancelled();
            } else {
                //速度计算
                mVelocityTracker.computeCurrentVelocity(1000,
                        ViewConfiguration.get(this).getScaledMaximumFlingVelocity());
                float velocityX = mVelocityTracker.getXVelocity(mActivePointerId);
                float velocityY = mVelocityTracker.getYVelocity(mActivePointerId);
                float velocity = mNavBarPosition.isRightEdge()
                        ? velocityX
                        : mNavBarPosition.isLeftEdge()
                                ? -velocityX
                                : velocityY;
                //更新一次上滑
                mInteractionHandler.updateDisplacement(getDisplacement(ev) - mStartDisplacement);
                //下发手势end
                mInteractionHandler.onGestureEnded(velocity, new PointF(velocityX, velocityY),
                        mDownPos);
        ...
    }

2、BaseSwipeUpHandlerV2.onGestureEnded

    public void onGestureEnded(float endVelocity, PointF velocity, PointF downPos) {
        float flingThreshold = mContext.getResources()
                .getDimension(R.dimen.quickstep_fling_threshold_velocity);
        //根据结束手势时的速度判断是否在猛扔
        boolean isFling = mGestureStarted && Math.abs(endVelocity) > flingThreshold;
        mStateCallback.setStateOnUiThread(STATE_GESTURE_COMPLETED);

        mLogAction = isFling ? Touch.FLING : Touch.SWIPE;
        boolean isVelocityVertical = Math.abs(velocity.y) > Math.abs(velocity.x);
        if (isVelocityVertical) {
            mLogDirection = velocity.y < 0 ? Direction.UP : Direction.DOWN;
        } else {
            mLogDirection = velocity.x < 0 ? Direction.LEFT : Direction.RIGHT;
        }
        mDownPos = downPos;
        //手势处理方法
        handleNormalGestureEnd(endVelocity, isFling, velocity, false /* isCancel */);
    }
2.1、BaseSwipeUpHandlerV2.handleNormalGestureEnd
    private void handleNormalGestureEnd(float endVelocity, boolean isFling, PointF velocity,
            boolean isCancel) {
        PointF velocityPxPerMs = new PointF(velocity.x / 1000, velocity.y / 1000);
        long duration = MAX_SWIPE_DURATION;
        float currentShift = mCurrentShift.value;
        //计算endTarget,也就是要去向home还是recent
        final GestureEndTarget endTarget = calculateEndTarget(velocity, endVelocity,
                isFling, isCancel);
        ...
        if (endTarget == HOME) {
            setShelfState(ShelfAnimState.CANCEL, LINEAR, 0);
            duration = Math.max(MIN_OVERSHOOT_DURATION, duration);
        } else if (endTarget == RECENTS) {
            ...
        }
        ...
        animateToProgress(startShift, endShift, duration, interpolator, endTarget, velocityPxPerMs);
    }
2.2、BaseSwipeUpHandlerV2.animateToProgress
    @UiThread
    private void animateToProgress(float start, float end, long duration, Interpolator interpolator,
            GestureEndTarget target, PointF velocityPxPerMs) {
        runOnRecentsAnimationStart(() -> animateToProgressInternal(start, end, duration,
                interpolator, target, velocityPxPerMs));
    }
2.3、BaseSwipeUpHandlerV2.animateToProgressInternal
    @UiThread
    private void animateToProgressInternal(float start, float end, long duration,
            Interpolator interpolator, GestureEndTarget target, PointF velocityPxPerMs) {
		...
        if (mGestureState.getEndTarget() == HOME) {
        	//创建动画
            HomeAnimationFactory homeAnimFactory = createHomeAnimationFactory(duration);
            //弹簧动画
            RectFSpringAnim windowAnim = createWindowAnimationToHome(start, homeAnimFactory);
            windowAnim.addAnimatorListener(new AnimationSuccessListener() {
                @Override
                public void onAnimationSuccess(Animator animator) {
                    if (mRecentsAnimationController == null) {
                        // If the recents animation is interrupted, we still end the running
                        // animation (not canceled) so this is still called. In that case, we can
                        // skip doing any future work here for the current gesture.
                        return;
                    }
                    // Finalize the state and notify of the change
                    mGestureState.setState(STATE_END_TARGET_ANIMATION_FINISHED);
                }
            });
            getOrientationHandler().adjustFloatingIconStartVelocity(velocityPxPerMs);
            //动画启动
            windowAnim.start(mContext, velocityPxPerMs);
            homeAnimFactory.playAtomicAnimation(velocityPxPerMs.y);
            mRunningWindowAnim = RunningWindowAnim.wrap(windowAnim);
            mLauncherTransitionController = null;
        } else {
            ...
        }
        ...
    }
2.4、createWindowAnimationToHome、windowAnim.start

createWindowAnimationToHome创建具体的变化动画,要修改松手动画内容就得改里面的动画效果逻辑。
windowAnim.start中动画启动,这里用的是SpringAnimation,并非Android原生的三种动画(补间动画、属性动画、帧动画)

SpringAnimation:

没有动画时间属性------setStiffnesssetDampingRatiosetStartVelocity根据刚值、阻尼系数、起始速度来决定动画时长。具体的可以百度一下SpringAnimation动画。

没有动画起始值和目标值------需要在update中计算每一帧界面,达到想要的效果。

3、跟手在哪里绘制

3.1、AndroidQ上
3.1.1、上下滑动跟手的处理:

OtherActivityInputConsumer#onMotionEvent
---mInteractionHandler.updateDisplacement
---WindowTransformSwipeHandler#updateDisplacement
---mCurrentShift.updateValue
---private final AnimatedFloat mCurrentShift = new AnimatedFloat(this::updateFinalShift);
---updateFinalShift
---

updateFinalShift

private void updateFinalShift() {
    float shift = mCurrentShift.value;

    SwipeAnimationTargetSet controller = mRecentsAnimationWrapper.getController();
    if (controller != null) {
    	//获取偏移量---对应手指左右滚动时,recent界面的ScrollX值
        float offsetX = mRecentsView == null ? 0 : mRecentsView.getScrollOffset();
        float offsetScale = getTaskCurveScaleForOffsetX(offsetX,
                mClipAnimationHelper.getTargetRect().width());
        //设置进度setProgress	这个表示上滑的进度,三方界面是0,上滑到recent时是1
        //偏移setOffsetX	X方向的滚动
        //offsetScale注意,这个值不是task的缩放值
        mTransformParams.setProgress(shift).setOffsetX(offsetX).setOffsetScale(offsetScale);
        //更新界面
        mClipAnimationHelper.applyTransform(mRecentsAnimationWrapper.targetSet,
                mTransformParams);
        updateSysUiFlags(shift);
    }
    ...
}

最终调用到ClipAnimationHelper.javaapplyTransform方法

    public RectF applyTransform(RemoteAnimationTargetSet targetSet, TransformParams params,
            boolean launcherOnTop) {
        // 根据progress缩放taskview的位置和大小
        float progress = params.progress;
        if (params.currentRect == null) {
            RectF currentRect;
            mTmpRectF.set(mTargetRect);
            Utilities.scaleRectFAboutCenter(mTmpRectF, params.offsetScale);
            // evaluate方法会根据progress整体变换rectF坐标和大小
			//计算当前显示的task大小,从这里可以看出task的大小是根据progress计算的
            currentRect = mRectFEvaluator.evaluate(progress, mSourceRect, mTmpRectF);
            Log.d("applyTransform","currentRect:  "+currentRect+" mSourceRect: "+mSourceRect+" mTmpRectF: "+mTmpRectF);
			//设置task偏移量
            currentRect.offset(params.offsetX, 0);
			...
        }
        ...
        //最终调用这里更新界面实现缩放和位移的效果
        applySurfaceParams(params.syncTransactionApplier, surfaceParams);
	}

如果要去掉上下跟手的效果,注释掉mInteractionHandler.updateDisplacement(displacement - mStartDisplacement);
,这里只是注释掉跟手效果的界面,手势判断还是有的,上滑up之后home,滑动停顿up之后recent。

3.1.2、左右跟手的处理:

OtherActivityInputConsumer.onMotionEvent
---mRecentsViewDispatcher.dispatchEvent(ev)
------mConsumer.accept(event)
---RecentsView.getEventDispatcher
------super::onTouchEvent
------PagedView.onTouchEvent
------scrollBy((int) deltaX, 0)

WindowTransformSwipeHandler.java中recentView设置滚动监听

mRecentsView.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
            if (mGestureEndTarget != HOME) {
                updateFinalShift();
            }
        });

这里就殊途同归了,也是走到updateFinalShift更新界面。

要想去掉左右跟手,注释掉
OtherActivityInputConsumer中关于mRecentsViewDispatcher的调用即可。
左右滑动底部快速切换Task整个功能也会没有。

private final CachedEventDispatcher mRecentsViewDispatcher = new CachedEventDispatcher();
mRecentsViewDispatcher.setConsumer(
mRecentsViewDispatcher.dispatchEvent(ev);

整个ev没有分发给PagedView.onTouchEvent进行界面滚动,松手后进入上一页还是下一页也无法计算得知。

注释掉mRecentsViewDispatcher并不会影响HOME、RECENT、NEW_TASK、LAST_TASK的计算,但是onTouchEvent没有调用到PagedView去,导致没有后续的松手切页。

—一些猜想,我们是否可以根据结束时的LAST_TASK、X的速度值,计算出左右切页,然后屏蔽掉左右跟手达到保留效果的目的。

从目前来看,三方界面左右滑动和up之后的切页,和桌面切页的逻辑是一样的,都是走PagedView.onTouchEvent里面。

如果只去掉跟手效果,保留功能,修改updateFinalShift中的offsetX = 0;就可以了

private void updateFinalShift() {
    float shift = mCurrentShift.value;

    SwipeAnimationTargetSet controller = mRecentsAnimationWrapper.getController();
    if (controller != null) {
        float offsetX = 0;//mRecentsView == null ? 0 : mRecentsView.getScrollOffset();
        float offsetScale = getTaskCurveScaleForOffsetX(offsetX,
                mClipAnimationHelper.getTargetRect().width());
        mTransformParams.setProgress(shift).setOffsetX(offsetX).setOffsetScale(offsetScale);
        mClipAnimationHelper.applyTransform(mRecentsAnimationWrapper.targetSet,
                mTransformParams);
        updateSysUiFlags(shift);
    }
    ...
}

后来验证这种方式有bug,只是注释掉了当前task的左右跟手,其它task还是会跟手动。
目前无法只去掉所有跟手效果而不影响功能。

3.2、AndroidR上
3.1.1、上下滑动跟手的处理:
在AndroidR上,和AndroidQ大同小异,只是代码结构发生了变化,类的名字变了。
上下滑动跟手事件传递

OtherActivityInputConsumer#onMotionEvent
---mInteractionHandler.updateDisplacement
---SwipeUpAnimationLogic#updateDisplacement---mCurrentShift.updateValue
---private final AnimatedFloat mCurrentShift = new AnimatedFloat(this::updateFinalShift);
---BaseSwipeUpHandlerV2.updateFinalShift
---

BaseSwipeUpHandlerV2.updateFinalShift

    @Override
    public void updateFinalShift() {
		...
        updateSysUiFlags(mCurrentShift.value);
        //更新当前task的缩放和位移
        applyWindowTransform();
        //更新其它task的缩放
        updateLauncherTransitionProgress();
    }

BaseSwipeUpHandler.applyWindowTransform

    /**
     * Applies the transform on the recents animation
     */
    protected void applyWindowTransform() {
    	//更新window动画的缩放
        if (mWindowTransitionController != null) {
            float progress = mCurrentShift.value / mDragLengthFactor;
            mWindowTransitionController.setPlayFraction(progress);
        }
        if (mRecentsAnimationTargets != null) {
        	//设置TaskViewSimulator的左右位移
            if (mRecentsViewScrollLinked) {
                mTaskViewSimulator.setScroll(mRecentsView.getScrollOffset());
            }
            //TaskViewSimulator是AndroidR上新增的类,用来处理taskview缩放和位移动画相关逻辑
            //方法内部具体计算和更新缩放+位移
            mTaskViewSimulator.apply(mTransformParams);
        }
    }

TaskViewSimulator.apply

    public void apply(TransformParams params) {
        if (mDp == null || mThumbnailPosition.isEmpty()) {
            return;
        }
        if (!mLayoutValid) {
            mLayoutValid = true;

            getFullScreenScale();
            mThumbnailData.rotation = mOrientationState.getDisplayRotation();

            mPositionHelper.updateThumbnailMatrix(
                    mThumbnailPosition, mThumbnailData,
                    mTaskRect.width(), mTaskRect.height(),
                    mDp, mOrientationState.getRecentsActivityRotation());
            mPositionHelper.getMatrix().invert(mInversePositionMatrix);

            PagedOrientationHandler poh = mOrientationState.getOrientationHandler();
            mScrollState.halfPageSize =
                    poh.getPrimaryValue(mTaskRect.width(), mTaskRect.height()) / 2;
            mScrollState.halfScreenSize = poh.getPrimaryValue(mDp.widthPx, mDp.heightPx) / 2;
            mScrollValid = false;
        }

        if (!mScrollValid) {
            mScrollValid = true;
            int start = mOrientationState.getOrientationHandler()
                    .getPrimaryValue(mTaskRect.left, mTaskRect.top);
            mScrollState.screenCenter = start + mScrollState.scroll + mScrollState.halfPageSize;
            mScrollState.updateInterpolation(start, mPageSpacing);
            mCurveScale = TaskView.getCurveScaleForInterpolation(mScrollState.linearInterpolation);
        }

        float progress = Utilities.boundToRange(fullScreenProgress.value, 0, 1);
        mCurrentFullscreenParams.setProgress(
                progress, recentsViewScale.value, mTaskRect.width(), mDp, mPositionHelper);

        // Apply thumbnail matrix
        RectF insets = mCurrentFullscreenParams.mCurrentDrawnInsets;
        float scale = mCurrentFullscreenParams.mScale;
        float taskWidth = mTaskRect.width();
        float taskHeight = mTaskRect.height();

        mMatrix.set(mPositionHelper.getMatrix());
        mMatrix.postTranslate(insets.left, insets.top);
        mMatrix.postScale(scale, scale);

        // Apply TaskView matrix: translate, scale, scroll
        mMatrix.postTranslate(mTaskRect.left, mTaskRect.top);
        mMatrix.postScale(mCurveScale, mCurveScale, taskWidth / 2, taskHeight / 2);
        mOrientationState.getOrientationHandler().set(
                mMatrix, MATRIX_POST_TRANSLATE, mScrollState.scroll);

        // Apply recensView matrix
        mMatrix.postScale(recentsViewScale.value, recentsViewScale.value, mPivot.x, mPivot.y);
        applyWindowToHomeRotation(mMatrix);
        Log.d("apply","progress: "+progress+" mTaskRect.left: "+mTaskRect.left+" mTaskRect.top: "+mTaskRect.top+" mCurveScale: "+mCurveScale+" mScrollState.scroll: "+mScrollState.scroll);
        // Crop rect is the inverse of thumbnail matrix
        mTempRectF.set(-insets.left, -insets.top,
                taskWidth + insets.right, taskHeight + insets.bottom);
        mInversePositionMatrix.mapRect(mTempRectF);
        mTempRectF.roundOut(mTmpCropRect);

        params.applySurfaceParams(params.createSurfaceParams(this));
    }

这里添加log发现:
1、progress控制进度,三方应用上滑到recent时,progress 1 — 0
2、mScrollState.scroll控制左右位移,所有滑动时跟手变化。
3、mCurveScale并非上滑时,taskView缩放,这个值一直是1
4、recentsViewScale.value是task当前的缩放值,三方界面的时候最大----recent大小的时候是1—继续上滑会小于1。松手后会恢复到recent大小 1 的状态
上滑:1.19—1—0.5 松手:?—1

apply方法只控制当前三方应用的位移和缩放,其它Task的缩放和位移不受影响。
注释掉applyWindowTransform,上下左右手势都不跟手,当前三方页面全屏,无法直接观察其它task的移动情况。使用布局工具动态跟踪,发现其它task是在位移的。

TaskViewSimulator只是负责更新当前task控制动画效果。
具体怎么控制当前task和其它task区分,暂时没有头绪

如果要去掉上下跟手效果
方案1:

com/android/quickstep/BaseActivityInterface.java
        protected void createBackgroundToOverviewAnim(ACTIVITY_TYPE activity, PendingAnimation pa) {
            //  Scale down recents from being full screen to being in overview.
            RecentsView recentsView = activity.getOverviewPanel();
            //注释掉其它task的缩放跟手
//            pa.addFloat(recentsView, SCALE_PROPERTY,
//                    recentsView.getMaxScaleForFullScreen(), 1, LINEAR);
            pa.addFloat(recentsView, FULLSCREEN_PROGRESS, 1, 0, LINEAR);
        }
com/android/quickstep/util/TaskViewSimulator.java
    public void addAppToOverviewAnim(PendingAnimation pa, TimeInterpolator interpolator) {
        pa.addFloat(fullScreenProgress, AnimatedFloat.VALUE, 1, 0, interpolator);
        //注释掉当前task的缩放
        //pa.addFloat(recentsViewScale, AnimatedFloat.VALUE, getFullScreenScale(), 1, interpolator);
    }
    public void apply(TransformParams params) {
        if (mDp == null || mThumbnailPosition.isEmpty()) {
            return;
        }
        //apply时给当前task缩放赋默认值
        recentsViewScale.value = getFullScreenScale();
        ...
    }

方案2

    if (mPassedWindowMoveSlop) {
        // Move
        //mInteractionHandler.updateDisplacement(displacement - mStartDisplacement);
    }

3.1.2、左右跟手的处理:
和AndroidQ类似

OtherActivityInputConsumer.onMotionEvent
---mRecentsViewDispatcher.dispatchEvent(ev)
------mConsumer.accept(event)
---RecentsView.getEventDispatcher
------super::onTouchEvent
------PagedView.onTouchEvent
---mOrientationHandler.set(this, VIEW_SCROLL_BY, (int) delta);

PagedView.java
public void scrollBy(int x, int y) {
    mOrientationHandler.delegateScrollBy(this, getUnboundedScroll(), x, y);
}

PortraitPagedViewHandler.java
public void delegateScrollBy(PagedView pagedView, int unboundedScroll, int x, int y) {
    pagedView.scrollTo(unboundedScroll + x, pagedView.getScrollY() + y);
}

quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
监听滚动事件更新,调用updateFinalShift和AndroidQ有点类似,最终也是在updateFinalShift中更新界面。

    protected void linkRecentsViewScroll() {
        SurfaceTransactionApplier.create(mRecentsView, applier -> {
            mTransformParams.setSyncTransactionApplier(applier);
            runOnRecentsAnimationStart(() ->
                    mRecentsAnimationTargets.addReleaseCheck(applier));
        });

        mRecentsView.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
            if (moveWindowWithRecentsScroll()) {
                updateFinalShift();//更新界面
            }
        });
        runOnRecentsAnimationStart(() ->
                mRecentsView.setRecentsAnimationTargets(mRecentsAnimationController,
                        mRecentsAnimationTargets));
        mRecentsViewScrollLinked = true;
    }

com/android/quickstep/BaseSwipeUpHandler.java

    protected void applyWindowTransform() {
        if (mWindowTransitionController != null) {
            float progress = mCurrentShift.value / mDragLengthFactor;
            mWindowTransitionController.setPlayFraction(progress);
        }
        if (mRecentsAnimationTargets != null) {
        	//这个注释掉只能去掉当前task的位移,上滑之后左右滑动,其它的task还是会左右滚动
//            if (mRecentsViewScrollLinked) {
//                mTaskViewSimulator.setScroll(mRecentsView.getScrollOffset());
//            }
            mTaskViewSimulator.apply(mTransformParams);
        }
    }

暂时没有办法只去掉其它task的位移跟手,而不影响Quickswitch功能。
怀疑Q上也没有,是不是当时调试漏掉了现象。。。后面再check一遍

要想去掉左右跟手,注释掉
OtherActivityInputConsumer中关于mRecentsViewDispatcher的调用即可。
左右滑动底部快速切换Task整个功能也会没有。

private final CachedEventDispatcher mRecentsViewDispatcher = new CachedEventDispatcher();
mRecentsViewDispatcher.setConsumer(
mRecentsViewDispatcher.dispatchEvent(ev);

3.3、AndroidS上

呼呼,累了,流程看的头晕眼花,S上的先不写了。。。后续有需求再跟吧

尾注

以上,三方界面上滑的跟手、左右滑动的跟手、松手之后的动画,介绍完毕。

新增的知识点:

1、launcher上滑和左右滑动整套流程简介
2、SpringAnimation动画
3、SyncRtSurfaceTransactionApplierCompat 更新界面

    public void applySurfaceParams(SurfaceParams[] params) {
        if (mSyncTransactionApplier != null) {
            mSyncTransactionApplier.scheduleApply(params);
        } else {
            TransactionCompat t = new TransactionCompat();
            for (SurfaceParams param : params) {
                SyncRtSurfaceTransactionApplierCompat.applyParams(t, param);
            }
            t.apply();
        }
    }

4、mSyncTransactionApplier
SurfaceTransactionApplier.create传入了recentView创建的。
这个之前没遇到过,不清楚具体的界面细节

SurfaceTransactionApplier.create(mRecentsView, applier -> {
            mTransformParams.setSyncTransactionApplier(applier);
            runOnRecentsAnimationStart(() ->
                    mRecentsAnimationTargets.addReleaseCheck(applier));
        });

5、不同的Android版本上滑处理会有些许差异,参考的时候需要自行研究一下

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值