问题背景
客户在低配置机器上,原生的三方应用界面上滑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:
没有动画时间属性------setStiffness
、setDampingRatio
、setStartVelocity
根据刚值、阻尼系数、起始速度来决定动画时长。具体的可以百度一下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.java
的applyTransform
方法
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版本上滑处理会有些许差异,参考的时候需要自行研究一下