systemui statusbar touch

本文深入剖析状态栏下拉动画的工作原理,包括触摸事件处理、动画触发与执行过程,以及动画状态转换机制。详细解释了mQsExpanded、mExpandedFraction等关键变量的作用,以及它们如何影响状态栏的展开与收缩。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  网上无意间看到的 流程,先留着 

mOnlyAffordanceInThisMotion:
mQsTouchAboveFalsingThreshold
mIsExpanding  是否是正在展开。。。。
mHintAnimationRunning
mQsExpanded  主要表述QSPanel是否是展开,即下拉状态,当第一段下拉时,由于QSPanel并没有移动,所以可以理解成QSPanel并没有展开,当第二次下拉时,该值为true,直到和第一次下拉的状态相同时,又变成false
mStatusBar.getBarState()   状态栏的状态,有SHADE “正常”的阴影模式;KEYGUARD 锁屏状态; SHADE_LOCKED 状态栏是在特殊模式下,它是完全互动的,但仍然锁定。所以把阴影仍然显示的保镖;我们只需要研究SHADE状态;
mQsFullyExpanded   QSPanel是否下拉完成(到底部),它是一个结束标志;
mExpandedFraction  展开比例,它的值在0到1之间,它是针对于第一次下拉和第二次收缩的,与第一次下拉和第二次收缩时手指move的距离有关;当该值为1以后,接下来就可以展开或者收缩QSPanel了;
mQsExpansionEnabled  QSPanel展开功能是否激活,一般情况下都是true,表示可以展开QSPanel;
mQsTracking    追踪QSPanel
mConflictingQsExpansionGesture
mExpandedHeight
mQsExpandImmediate
mTwoFingerQsExpandPossible
mStatusBarMinHeight
mInitialHeightOnTouch   onTouch手势时的初始高度
mQsExpansionHeight      QSPanel的展开高度,它的初始值是102.0;QSPanel没有展开时,该值即为102.0;展开以后,该值便在102.0的基础上加上相应的值


状态栏touch事件一.:第一次迅速down事件  http://blog.sina.com.cn/s/blog_14df9d9d80102wdmv.html

1.touch事件首先是传递给了PanelHolder,但是PanelHolder没有消费,事件继续传递给PhoneStatusBarView,
而PhoneStatusBarView的子view也没有消费,所以事件最终传递给了PhoneStatusBarView的onTouchEvent(),交由它的父view-->PanelBar消费;
在PanelBar的onTouchEvent()中,事件传递给了下拉状态栏NotificationPanelView处理;
研究下NotificationPanelView的onTouchEvent()函数:
由于该手势动作只是一个很普通的down事件,NotificationPanelView的onTouchEvent()几乎没做任何处理(除了双指操作,这个以后分析),直接把down事件传递给它的父view--->PanelView;


2.分析PanelView的OnTouchEvent();
首先,由于mExpandedHeight ==0;
所以  mGestureWaitForTouchSlop为true,mGestureWaitForTouchSlop会在发生每一次down事件时,判断下拉状态栏的下拉高度是否为0;
开始分析down事件在view中传递了,
首先是mInitialTouchY,mInitialTouchX: 这两个代表手指在view中的初始x,y坐标;
mInitialOffsetOnTouch: 表示初始化手指在view中的偏移量,它的值等于mExpandedHeight,由于这里状态栏还没有下拉,所以为0;
mTouchSlopExceeded: 表示是否超出手指移动距离的保守值,一旦超过,就可以做其他操作,如果展开QSPanel等,刚开始为false;
mJustPeeked:  表示是否仅仅是执行peek偷看动画的操作,默认为false;
mPanelClosedOnDown: 表示down事件是否发生在下拉状态栏关闭的状态,它的判断条件是mExpandedHeight == 0.0f,默认为true;

以上是分析这次手势的关键参数,而且他们此刻的值也只是在当前手势下的,不同的动作会有不同的值,后面再分析;

3.由于mExpandedHeight == 0 因此执行schedulePeek()(执行偷看动画) 该函数就是此次手势的重点:

4.schedulePeek()函数分析:
首先,mPeekPending =true,表示即将发生mPeekAnimator动画,在等待mPeekAnimator动画;
然后将mPeekRunnable放入消息队列;
接下来执行notifyBarPanelExpansionChanged()函数,该函数操作着整个状态栏的高度,让状态栏显示在显示状态栏和下拉状态栏中自如切换;

5.先看notifyBarPanelExpansionChanged()函数,该函数最终调用的PanelBar中的panelExpansionChanged()函数:
由于此时的mExpandedHeight = 0,所以下拉状态栏现在还不可见,但是由于mPeekPending =true,表示即将发生mPeekAnimator动画,
而mPeekAnimator动画是作用于下拉状态栏中的,所以此时需要让状态栏的高度变成下拉状态栏的;
而状态栏高度的变化,会调用onLayout()函数的调用;

6.在onLayout()中,会操作它的子view,如HeaderView,通知栏,快捷栏等;
在这里,有两个值需要特别强调下:
mQsMinExpansionHeight  
mHeader.getCollapsedHeight() 90 mQsPeekHeight
12  ----> 102 ;

mQsMaxExpansionHeight  
mHeader.getExpandedHeight() 174 mQsContainer.getDesiredHeight()
555 ----> 729 ;
这两个值会影响这后面的分析;
然后调用setQsExpansion()函数,该函数相当重要,操作着HeaderView,通知栏,快捷栏的位置以及大小,以及设置mQsExpanded;


7.分析setQsExpansion()函数:
因为这次函数的比较简单,所以分析的也就比较简单,后面在分析;
首先,height = Math.min(Math.max(height, mQsMinExpansionHeight),
mQsMaxExpansionHeight);
所以, height = 102 ,因此 mQsExpansionHeight = 102;
由此可见,mQsExpansionHeight的起始值就是mQsMinExpansionHeight;
然后处理通知栏,快捷栏的位置以及大小,后面再说;

8.在PanelBar中,由于当前的mState == STATE_CLOSED,让mState 的 值调整成
STATE_OPENING,表示正在展开;
然后调用onPanelPeeked()方法,该方法会调用PhoneStatusBar中的makeExpandedVisible(false)函数,将状态栏的高度调整为全屏,准备显示下拉状态栏了;

9.再回到mPeekRunnable函数体:
首先mPeekPending = false,在这里表示立即mPeekAnimator动画,不再等待;
然后执行runPeekAnimation()函数,真正的偷看动画来了;

10.runPeekAnimation()函数:
mPeekAnimator 即 偷看动画,而 mPeekHeight 为动画的最终值;
在 mPeekAnimator动画执行之前,还需要执行notifyExpandingStarted()函数,通知展开开始:
我们先来看一下 notifyExpandingStarted() 函数 ;

11.notifyExpandingStarted()函数:
首先是 mExpanding = true--------> 表示正在展开中;
然后调用onExpandingStarted()------->展开开始时需要进行的操作;
该函数先是通知通知栏的展开开始 
mNotificationStackScroller.onExpansionStarted();
然后是 mIsExpanding = true 表示正在展开;
mQsExpandedWhenExpandingStarted = mQsFullyExpanded;
mQsExpandedWhenExpandingStarted 表示的是当展开开始时,QSPanel的当前下拉状态,这里它的值为mQsFullyExpanded,表示QSPanel是否下拉到底部了,在这里它的值为false;

12.接着回到runPeekAnimation()函数体,开始执行偷看动画了;
执行动画的同时,mJustPeeked = true;表示这次仅仅是执行偷看操作;
	
13.mPeekAnimator是属性动画,动画的执行,伴随着setExpandedHeight()函数的调用;
而setExpandedHeight(float height)的代理函数是setExpandedHeightInternal();
height 即是 偷看动画的 取值;

14.setExpandedHeightInternal()函数分析:
首先是,float fhWithoutOverExpansion = getMaxPanelHeight() - getOverExpansionAmount();
此手势下,fhWithoutOverExpansion = getMaxPanelHeight() = 636;
mExpandedHeight = h ,即peek动画的高度;
mExpandedFraction = mExpandedHeight / fhWithoutOverExpansion;
然后通过onHeightUpdated(mExpandedHeight);函数改变各子view的布局;
最后调用notifyBarPanelExpansionChanged()函数,此时notifyBarPanelExpansionChanged()的内部方法已经有变化;
此时,pv.getExpandedHeight() > 0,所以下拉状态栏可见;



状态栏touch事件二:迅速down之后的up事件,偷看动画以及up事件的后续效果

1.因为NotificationPanelView的onTouchEvent()的返回值被强制返回了true,所以这次的up事件也是在NotificationPanelView的onTouchEvent()中
     执行的,和down事件一样,在NotificationPanelView的onTouchEvent()中up事件也并没有做其他处理,直接交给PanelView;

2.PanelView的ontouchevent()函数:
     直接看MotionEvent.ACTION_UP:由于之前的down事件比较简单,很多参数没有被赋值,即都是初始化的值,所以在up事件的处理中,直接走
     boolean expands = onEmptySpaceClick(mInitialTouchX);
     onTrackingStopped(expands);

3.先看onEmptySpaceClick(mInitialTouchX)函数:mInitialTouchX表示初始化时touch在view中x坐标值;
     onEmptySpaceClick() ---->onMiddleClicked() ---> post(mPostCollapseRunnable)并返回false;

4.观察mPostCollapseRunnable 函数体,其实它执行的是收缩状态栏的方法体;替代函数是collapse(false );
     再来看collapse(false):false表示不延迟;
     此手势的up事件是在动画结束之前执行的,所以此时的mPeekAnimator != null,因此mCollapseAfterPeek = true,表示在偷看操作之后要进行收缩状态栏的操作;

5.再回到mPeekAnimator动画的监听器,当动画结束以后,将动画赋值为null,即mPeekAnimator = null;
     又执行一次collapse(false),并且将mCollapseAfterPeek = false;
     此时collapse(false)内部的函数执行方式又发生了变化,因为mPeekAnimator == null,所以走fling(0, false )函数;
6.分析fling(0, false ):false表示不展开;
     先是调用cancelPeek():清除peek动画和队列中的mPeekRunnable方法体,并mPeekPending = false,表示不再等待peek动画执行;
     因为expand为false;所以动画的目标值target为0;
     接着是创建属性动画animator,然后定义animator,设置动画的结束监听,并将animator赋给mHeightAnimator,动画开始;

7.mHeightAnimator动画在运行过程中,会调用setExpandedHeightInternal()函数,该函数在之前研究过,它会改变各view的大小和位置;
     当mHeightAnimator动画结束时,设置mHeightAnimator = null;
     并调用notifyExpandingFinished();通知展开结束;
8.notifyExpandingFinished()函数:
     mExpanding = false;
     onExpandingFinished()  ---> 通知通知栏展开停止,mIsExpanding = false;mQsExpandImmediate = false;
     因为mExpandedHeight == 0f,所以setListening(false);不再监听;
9.再回到onTrackingStopped(expands),这里的expands为false,表示不展开,它是手势结束后最后一个执行的函数;同时它也会执行关于锁屏界面的相关操作,这个后面分析;
     该函数会执行:mTracking = false,表示不再跟踪 ;   



状态栏touch事件三:手指触摸状态栏,进行第一次下拉,直到底部   http://blog.sina.com.cn/s/blog_14df9d9d80102wdpa.html 

1.这次的手势,是从显示状态栏开始下拉,一直下拉到底部,此次分析的是down,move和up;
   2.还是先从NotificationPanelView的onTouchEvent()函数分析起,由于是第一次下拉,down事件几乎不做处理,直接交给PanelView;
     和第一次迅速down的事件一样,开启peek偷看动画,但是不同的是,在peek动画结束时,此时mCollapseAfterPeek为false,所以不做收缩动作;
     动画结束后,view会保持动画结束后的效果,等待下一布操作;

3.move事件分析:
     h = y - mInitialTouchY; h 为 手指在屏幕上移动的y轴方向上的距离;
     当h大于mTouchSlop,即系统默认偏移量时,mTouchSlopExceeded = true,表示超出手指移动距离的保守值;
     由于此时的waitForTouchSlop 为 true,mTracking为 false,则
     cancelHeightAnimator(); 清除掉mHeightAnimator动画,即手指up事件后的释放动画;
     removeCallbacks(mPeekRunnable); 清除队列中的mPeekRunnable;
     mPeekPending = false;  不再等待peek动画;
     onTrackingStarted(), 追踪开始; mTracking = true,正在追踪;mCollapseAfterPeek = false,peek动画后不收缩状态栏;
     再看下面这一句:
final float newHeight = Math.max(0, h + mInitialOffsetOnTouch);
     newHeight即为h,手指在屏幕上移动的y轴方向上的距离;
     一旦newHeight > mPeekHeight,即手指移动距离大于peek动画的最终高度,此时若是mPeekAnimator != null,
     则mPeekAnimator.cancel(),peek动画立即取消,view停留在当前动画停止的位置,并mJustPeeked = false,表示当前的操作不仅仅是peek,
     还有后续动作;
     当所有的条件都满足时,执行setExpandedHeightInternal(newHeight);

4.setExpandedHeightInternal(newHeight)函数分析:newHeight为手指在屏幕上移动的y轴方向上的距离;
     该函数中会用到很多关于通知栏的参数,通知栏太复杂,这里先不研究,这里有几个结论:
     setOverExpansion(overExpansionPixels, true ); 第一次下拉到一定位置时,改变QSPanel的位置;
     mExpandedHeight 的大小也在被限制着,并不是newHeight;

5.up事件分析:
     先看这一句:expand = flingExpands(vel, vectorVel),判断up事件后状态栏是展开还是收缩;
     我们来研究一下flingExpands(vel, vectorVel)函数:vel表示手指速度;
     当手指速度小于一个临界值时,是否展开的依据是getExpandedFraction() > 0.5f,即下拉比例是否超过一半;
     当手指速度过大时,直接判断手指是上滑还是下滑;
     然后,调用onTrackingStopped(expand)函数,执行通知栏的up手势动画以及锁屏,并且mTracking = false;
     最后调用fling(vel, expand),vel表示速度,expand表示是否展开;
     关于fling(vel, expand),在之前已经分析过,这里不再叙述;

6.我们来研究下动画执行中的setExpandedHeightInternal()的调用;
     mExpandedHeight 的 值为h;
     mExpandedFraction一直在增大,最终为1;
     当expand为true,展开动画结束时,    mExpandedFraction为1,此时调用notifyBarPanelExpansionChanged(),分析该函数:
   7.notifyBarPanelExpansionChanged()函数分析:
     当下拉比例为1时,fullyOpenedPanel 即为状态栏,如果此时动画停止或者下拉停止了,mTracking为false,则调用go(STATE_OPEN);
     将状态改为STATE_OPEN;
   8.至此,分析结束;

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值