關於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界面的解決方法

最後

我在微信公衆號也有寫文章,更新比較及時,有興趣者能夠關注以下公衆號!

相關文章
相關標籤/搜索