点击下拉菜单空白处自动收起下拉菜单

首先

点击下拉菜单的空白处,下拉菜单自动收回功能在android12之后的版本中已经去除,只能通过上滑下拉菜单来收起下拉菜单

下拉菜单全屏显示的情况

以下修改适用于正常显示尺寸设备,下拉菜单占满全屏的情况,下拉菜单不能占满全屏的情况在后面处理

//想在android12之后的版本中也通过点击下拉菜单的空白处自动收起下拉菜单,修改如下
frameworks/base/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
//处理点击下拉菜单空白处的逻辑
private void onEmptySpaceClick() {
    if (!mHintAnimationRunning)  {
        onMiddleClicked();
    }
}
private void onMiddleClicked() {
    switch (mBarState) {
        case KEYGUARD:	//密码输入页面
            if (!mDozingOnDown) {
                mShadeLog.v("onMiddleClicked on Keyguard, mDozingOnDown: false");
                // Try triggering face auth, this "might" run. Check
                // KeyguardUpdateMonitor#shouldListenForFace to see when face auth won't run.
                mKeyguardFaceAuthInteractor.onNotificationPanelClicked();
                boolean didFaceAuthRun = mUpdateMonitor.requestFaceAuth(
                        FaceAuthApiRequestReason.NOTIFICATION_PANEL_CLICKED);

                if (didFaceAuthRun) {
                    mUpdateMonitor.requestActiveUnlock(
                            ActiveUnlockConfig.ActiveUnlockRequestOrigin.UNLOCK_INTENT,
                            "lockScreenEmptySpaceTap");
                } else {
                    mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_HINT,
                            0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
                    mLockscreenGestureLogger
                            .log(LockscreenUiEvent.LOCKSCREEN_LOCK_SHOW_HINT);
                    startUnlockHintAnimation();
                }
            }
            break;
        case StatusBarState.SHADE_LOCKED:	//锁屏页面的阴影处
            if (!mQsController.getExpanded()) {
                mStatusBarStateController.setState(KEYGUARD);
            }
        //添加的修改,阴影位置,点击下拉菜单的空白处返回SHADE
        case StatusBarState.SHADE:
            //参照android12的处理方式,在子线程中处理点击下拉菜单空白处的逻辑
            mView.post(mPostCollapseRunnable);
            break;
    }
}
//添加的代码,参考原生android12
protected final Runnable mPostCollapseRunnable = new Runnable() {
    @Override
    public void run() {
        collapse(false /* delayed */, 1.0f /* speedUpFactor */);
    }
};
//以下是android14现有代码
public void collapse(boolean delayed, float speedUpFactor) {
    if (!canBeCollapsed()) {
        return;
    }

    if (mQsController.getExpanded()) {
        mQsController.setExpandImmediate(true);
        setShowShelfOnly(true);
    }
    debugLog("collapse: %s", this);
    if (canBeCollapsed()) {
        cancelHeightAnimator();
        notifyExpandingStarted();

        // Set after notifyExpandingStarted, as notifyExpandingStarted resets the closing state.
        setClosing(true);
        if (delayed) {
            mNextCollapseSpeedUpFactor = speedUpFactor;
            this.mView.postDelayed(mFlingCollapseRunnable, 120);
        } else {
            fling(0, false /* expand */, speedUpFactor, false /* expandBecauseOfFalsing */);
        }
    }
}

不规则屏或者大屏幕设备,下拉菜单不能占满全屏时的处理方式

以下修改适用于大屏设备,下拉菜单无法占满全屏,只在屏幕中间居中显示

//下拉菜单view的控制器
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
//以下是android14现有代码,mView是自定义控件NotificationStackScrollLayout.java,点击事件在自定义控件中处理
private void setUpView() {
    ...
    //下拉菜单的触摸事件
    mView.setTouchHandler(new TouchHandler());
    ...
}

class TouchHandler implements Gefingerpoken {
    public boolean onInterceptTouchEvent(MotionEvent ev) {
    	...
        //拦截下拉菜单空白处的点击事件
        mView.handleEmptySpaceClick(ev);
        ...
    }
    
    public boolean onTouchEvent(MotionEvent ev) {
    	...
        //下拉菜单空白处的点击处理
        mView.handleEmptySpaceClick(ev);
        ....
    }
}
    
//现有的自定义控件
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
//下拉菜单空白处的点击处理
void handleEmptySpaceClick(MotionEvent ev) {
    ...
    switch (ev.getActionMasked()) {
        case MotionEvent.ACTION_MOVE:	//move事件
            final float touchSlop = getTouchSlop(ev);
            if (mTouchIsClick && (Math.abs(ev.getY() - mInitialTouchY) > touchSlop
                    || Math.abs(ev.getX() - mInitialTouchX) > touchSlop)) {
                mTouchIsClick = false;
            }
            break;
        case MotionEvent.ACTION_UP:		//up事件
            //android14现有代码
            //判断当前触摸事件的类型和所在页面,并且触摸位置是否在最后一个通知的下面
            //此处最终会执行到NotificationPanelViewController.java中的onEmptySpaceClicked函数中
            if (mStatusBarState != StatusBarState.KEYGUARD && mTouchIsClick &&
                    isBelowLastNotification(mInitialTouchX, mInitialTouchY)) {
                debugLog("handleEmptySpaceClick: touch event propagated further");
                mOnEmptySpaceClickListener.onEmptySpaceClicked(mInitialTouchX, mInitialTouchY);
            }
			//添加的修改,针对大屏幕中下拉菜单不能占据全屏的情况,点击的位置在通知区域的左右两边
            //isInContentBounds是天机的重写方法
            if (mStatusBarState != StatusBarState.KEYGUARD && mTouchIsClick && !isInContentBounds(ev.getX(),ev.getY())){
                mOnEmptySpaceClickListener.onEmptySpaceClicked(mInitialTouchX, mInitialTouchY);
            }
            break;
            ...
    }
}
//添加的修改,判断触摸位置是否是大屏中的下拉菜单的左右空白处
private boolean isInContentBounds(float x, float y) {
    int childCount = getChildCount();
    for (int i = childCount - 1; i >= 0; i--) {
        ExpandableView child = getChildAtIndex(i);
        if (child.getVisibility() != View.GONE) {
            float chidlWidth = child.getWidth();
            float childLeft =  child.getX();
            if (x > childLeft+chidlWidth || x < childLeft) {
                return false;
            }
        }
    }
    return true;
}

结语

android高版本已经放弃点击下拉菜单的空白处收起下拉菜单的功能,所以想要高版本中也有此功能可以按照以上部分修改,根据实际情况选择不同的处理方式或者‘全都要’
以上的修改并不能完美的解决下拉菜单自动回收的功能,还是有一点小瑕疵,比如下拉通知栏中有很多通知,有些相同类型的通知会折叠起来,此时如果点击展开折叠起来的通知,此时下拉菜单占满全屏的情况下点击空白位置,下拉通知不会自动收回,再次将通知折叠起来后又可以正常收回,这个情况暂时没有好的解决办法,所以自行选择吧

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值