关于Android状态栏高度为0仍显示的问题

前言

这里有一个比较坑的事,系统将状态栏的高度已经设置为0,而后界面上确实已经看不到时间,WiFi 等图标,也没法经过下拉,显示通知栏。但在某些应用的activity上,仍是会出现activity的状态栏,这个一开始还觉得是activity的标题栏,但到了后面,发现这是状态栏。java

应用层更改Activity的窗口风格

而这里的状态栏能够在activity的onCreate方法中经过以下方法隐藏掉:android

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Window window = getWindow();
    window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN);//隐藏状态栏

    setContentView(R.layout.activity_main);
}
复制代码

这里须要注意的是,全部的窗口属性设置,例如隐藏导航栏,隐藏标题栏,更改状态栏的颜色,都必须在调用以下方法以前:微信

setContentView(R.layout.activity_main);
复制代码

这是由于,在该执行该方法的时候,就开始去获取窗口的相关属性,而后去进行窗口的绘制,若是,在这以后再去设置属性,会出现报错或者设置无效的状况。app

经过系统更改Activity的窗口风格

但这次涉及修改的APP比较多,因此想经过系统来进行实现,将状态栏完全去掉。ide

既然在应用层中能够经过方法来解决问题,那么咱们只需在源码中搜索setContentView的具体实现,而后再找到合适的位置,在绘制窗口前进行设置便可。post

setContentView属于activity的方法,咱们查看该方法的实现:ui

frameworks/base/core/java/android/app/Activity.java
public void setContentView(View view) {
    getWindow().setContentView(view);
    initWindowDecorActionBar();
}
复制代码

这里经过getWindow方法去获取获取一个实例,而后再调用该实例中的方法。咱们先查看getWindow的实现:this

frameworks/base/core/java/android/app/Activity.java
public Window getWindow() {
    return mWindow;
}
复制代码

这里返回一个全局实例,继续查看该实例的实现,最后发现该实例实在activity的attach方法中实现:spa

frameworks/base/core/java/android/app/Activity.java
final void attach(Context context, ActivityThread aThread,
        Instrumentation instr, IBinder token, int ident,
        Application application, Intent intent, ActivityInfo info,
        CharSequence title, Activity parent, String id,
        NonConfigurationInstances lastNonConfigurationInstances,
        Configuration config, String referrer, IVoiceInteractor voiceInteractor,
        Window window, ActivityConfigCallback activityConfigCallback) {
        
    ....
    mWindow = new PhoneWindow(this, window, activityConfigCallback);
    mWindow.setWindowControllerCallback(this);
    mWindow.setCallback(this);
    mWindow.setOnWindowDismissedCallback(this);
    mWindow.getLayoutInflater().setPrivateFactory(this);
    if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
        mWindow.setSoftInputMode(info.softInputMode);
    }
    if (info.uiOptions != 0) {
        mWindow.setUiOptions(info.uiOptions);
    }
    
    ....
    mWindow.setWindowManager(
            (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
            mToken, mComponent.flattenToString(),
            (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
    if (mParent != null) {
        mWindow.setContainer(mParent.getWindow());
    }
    mWindowManager = mWindow.getWindowManager();
    mCurrentConfig = config;

    mWindow.setColorMode(info.colorMode);
    
    ...
}
复制代码

原来最终是经过PhoneWindow类的方法来实现,继续查看:code

frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java
public void setContentView(View view, ViewGroup.LayoutParams params) {
    // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
    // decor, when theme attributes and the like are crystalized. Do not check the feature
    // before this happens.
    if (mContentParent == null) {
        installDecor();
    } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        mContentParent.removeAllViews();
    }

    if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        view.setLayoutParams(params);
        final Scene newScene = new Scene(mContentParent, view);
        transitionTo(newScene);
    } else {
        mContentParent.addView(view, params);
    }
    mContentParent.requestApplyInsets();
    final Callback cb = getCallback();
    if (cb != null && !isDestroyed()) {
        cb.onContentChanged();
    }
    mContentParentExplicitlySet = true;
}
复制代码

首次启动activity的时候,mContentParent为null,那么就会先执行installDecor方法,进来看看该方法的实现:

frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java
private void installDecor() {
    ....
    if (mContentParent == null) {
        mContentParent = generateLayout(mDecor);
        ....
    }
    ....
}
复制代码

mContentParent经过generateLayout得到实例,咱们看下generateLayout方法的实现:

frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java
protected ViewGroup generateLayout(DecorView decor) {
    TypedArray a = getWindowStyle();
    final Context context = getContext();
    final Context context = getContext();
    ....
    mIsFloating = a.getBoolean(R.styleable.Window_windowIsFloating, false);
    int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)
            & (~getForcedWindowFlags());
    if (mIsFloating) {
        setLayout(WRAP_CONTENT, WRAP_CONTENT);
        setFlags(0, flagsToUpdate);
    } else {
        setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate);
    }

    if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {
        requestFeature(FEATURE_NO_TITLE);
    } else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) {
        // Don't allow an action bar if there is no title.
        requestFeature(FEATURE_ACTION_BAR);
    }

    if (a.getBoolean(R.styleable.Window_windowActionBarOverlay, false)) {
        requestFeature(FEATURE_ACTION_BAR_OVERLAY);
    }

    if (a.getBoolean(R.styleable.Window_windowActionModeOverlay, false)) {
        requestFeature(FEATURE_ACTION_MODE_OVERLAY);
    }

    if (a.getBoolean(R.styleable.Window_windowSwipeToDismiss, false)) {
        requestFeature(FEATURE_SWIPE_TO_DISMISS);
    }
    //add by mnq. 隐藏状态栏 @{
    if (context.getResources().getBoolean(R.bool.cvte_hide_activity_statusbar) || a.getBoolean(R.styleable.Window_windowFullscreen, false)) {
        setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN & (~getForcedWindowFlags()));
    }
    //add by mnq. 隐藏状态栏 @}

    if (a.getBoolean(R.styleable.Window_windowTranslucentStatus,
            false)) {
        setFlags(FLAG_TRANSLUCENT_STATUS, FLAG_TRANSLUCENT_STATUS
                & (~getForcedWindowFlags()));
    }
    ....
}
复制代码

在与getWindowStyle四目相对的那一刻,我就知道,咱们要找的地方到了。继续往下查看,果真都是一些设置Window风格的语句,在这里找到了咱们此次的目标:

if ( a.getBoolean(R.styleable.Window_windowFullscreen, false)) {
        setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN & (~getForcedWindowFlags()));
}
复制代码

这里是经过去读取相关的资源配置,若是配置了Window全屏显示,则设置FLAG_FULLSCREEN的flag,而后Window在绘制的时候,就会进行全屏显示,而不会有状态栏。

而这个资源配置,则是各个APP的Androidmanifest中进行配置的Window风格。显然咱们改动不了这里。但咱们能够在这里增长一个配置,而后在overlay中进行配置实现:

1.
frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java
//add by mnq. 隐藏状态栏 @{
if (context.getResources().getBoolean(R.bool.cvte_hide_activity_statusbar) || a.getBoolean(R.styleable.Window_windowFullscreen, false)) {
        setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN & (~getForcedWindowFlags()));
}
//add by mnq. 隐藏状态栏 @}

2.
frameworks/base/core/res/res/values/config.xml
<!-- add by mnq. 隐藏状态栏 @{ -->
<bool name="cvte_hide_activity_statusbar">false</bool>
<!-- add by mnq. 隐藏状态栏 @} -->

3.
frameworks/base/core/res/res/values/symbols.xml
<!-- add by mnq. 隐藏状态栏 @{ -->
<java-symbol type="bool" name="cvte_hide_activity_statusbar" />
<!-- add by mnq. 隐藏状态栏 @} -->
复制代码

以上就至关于在系统中增长了一个配置,该配置能够经过overlay去配置是否要经过系统来强制隐藏activity的状态栏。

总结

因此,全部在Androidmanifest中配置的窗口风格,皆能够在这里经过系统去强制改写。

固然,可以在Androidmanifest中进行配置就最好了。

互动

若是文章存在错误描述,可直接留言,一块儿探讨!

可能感兴趣的文章

踩坑之默认输入法配置

踩坑之NavigationBar 的隐藏与否

关于Android9.0开机黑屏一段时间才加载launcher界面的解决方法

最后

我在微信公众号也有写文章,更新比较及时,有兴趣者能够关注以下公众号!

相关文章
相关标签/搜索