当前位置: 代码网 > it编程>App开发>Android > Launcher三方应用界面手势

Launcher三方应用界面手势

2024年08月03日 Android 我要评论
是task当前的缩放值,三方界面的时候最大----recent大小的时候是1—继续上滑会小于1。使用布局工具动态跟踪,发现其它task是在位移的。,这里只是注释掉跟手效果的界面,手势判断还是有的,上滑up之后home,滑动停顿up之后recent。在AndroidR上,和AndroidQ大同小异,只是代码结构发生了变化,类的名字变了。没有动画起始值和目标值------需要在update中计算每一帧界面,达到想要的效果。客户在低配置机器上,原生的三方应用界面上滑home动画负载太重,动画效果卡顿。

问题背景

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

中介绍了一些手势的知识

之前有关于这部分的简单逻辑 参考第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版本上滑处理会有些许差异,参考的时候需要自行研究一下

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com