• 熱門專題

分別用ToolBar和自定義導航欄實現沉浸式狀態欄

作者:熊,我-  發布日期:2016-12-26 20:23:29
Tag標簽:別用  狀態  
  • 一、ToolBar

    1、在build.gradle中添加依賴,例如:

    compile 'com.android.support:appcompat-v7:23.4.0'

    2、去掉應用的ActionBar?梢允切薷闹黝}theme為“NoActionBar”,例如:

    <style name='AppTheme' parent='Theme.AppCompat.Light.NoActionBar'>
    

    或者不修改主題為'NoActionBar',而在主題的style下,添加:

        <item name='windowNoTitle'>true</item>
        <item name='windowActionBar'>false</item>

    第二個屬性代表是否用ActionBar代替TitleBar。

    其實,剛學的時候,感覺很納悶,怎么又多了個TitleBar?后來查了很久才發現,3.0以前,狀態欄下面的是標題欄(只能顯示標題等少量信息),3.0以后就變成了應用欄,也就是ActionBar。

    另外,我測試的時候,activity是繼承于AppCompatActivity,主題是AppCompat類型的。這種情況下,必須要像上面那樣寫才有效果,少寫或值不同的話,要么沒效果,要么報錯。

    最后,上面兩個屬性的說明可在android.R.attr這個類中查看。

    3、在xml中為ToolBar添加屬性

        android:fitsSystemWindows='true'
        android:minHeight='?attr/actionBarSize'

    fitsSystemWindows是ToolBar實現沉浸式狀態欄的關鍵,其大概情況是,如果設為true,就會調整這個view去留一些空間給系統窗口,如果不設置或設為false,ToolBar就會和狀態欄重疊在一起。

    而第二個屬性中,它的值全寫是'?android:attr/actionBarSize',其意思是引用當前主題中的actionBarSize這個屬性。更多相關說明可查看官方文檔中Accessing Resources的部分。

    上面兩個屬性可在android.view.View這個類中查看。

    4、在java中添加判斷sdk版本的代碼并在用戶的系統是4.4及以上時設置狀態欄為透明

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            }

    無論是ToolBar,還是自定義導航欄,這個操作都是實現沉浸式狀態欄的關鍵。

    因為設置狀態欄為透明的這個屬性,要4.4以上才能使用,所以4.4以下的系統是不能夠實現沉浸式狀態欄的。而在4.4到5.0的系統中,狀態欄是全透明的,也就是它的顏色會跟你的ToolBar和自定義導航欄的顏色一樣。而在5.0以上的系統中,則是半透明的,也就看起來會比較深暗。

    而我在6.0的系統上測試時,發現這一步沒設置和設置了的,從效果上看,區別就是沒設置時狀態欄顏色淺一點,而且ToolBar的padding top為0,而設置了的顏色就深一點,padding top為狀態欄的高度。具體有什么影響,還不清楚。但這會讓自定義導航的外觀變形,它會增加狀態欄的高度,但又沒有讓這部分與狀態欄重疊,就導致效果變形。

    5、最后在java中添加

    setSupportActionBar(mToolbar);

    ToolBar的布局代碼:

    <?xml version='1.0' encoding='utf-8'?>
    <android.support.v7.widget.Toolbar
        xmlns:android='http://schemas.android.com/apk/res/android'
        xmlns:app='http://schemas.android.com/apk/res-auto'
        android:id='@+id/tool_bar'
        android:layout_width='match_parent'
        android:layout_height='wrap_content'
        android:background='@color/colorPrimary'
        android:elevation='4dp'
        android:fitsSystemWindows='true'
        android:minHeight='?android:attr/actionBarSize'
        app:title='ToolBar'
        app:subtitle='toolbar'/>

     效果圖(Android 6.0):

    二、自定義導航欄TopBar

    1、設置窗口為無標題,上面第2步中的兩個方法都可以實現,或者是在java中添加如下代碼:

            requestWindowFeature(Window.FEATURE_NO_TITLE);
    

    注意在添加這句代碼時,確保是在加載布局內容之前,也就是onCreate的setContentView之前。

    另外,我發現如果該activity是繼承AppCompatActivity的話,只寫上面的這句代碼是沒有變化的,顯示的還是ActionBar。但如果是繼承FragmentActivity的話,就有效果,也就說上面第2步中的第二個方法,只添加其中任意一個屬性都是可以的。至于是什么原因,我還沒弄清楚。

    2、同上面第4步,判斷系統版本并按需設置狀態欄為透明

    3、獲取狀態欄的高度

        protected int getStatusHeight() {
            try {
                Class<?> c = Class.forName('com.android.internal.R$dimen'); // 獲得與字符串對應的Class對象
                Object object = c.newInstance(); // 創建這個Class的實例對象
                Field field = c.getField('status_bar_height'); // 拿到字符串對應的變量
                int x = Integer.parseInt(field.get(object).toString()); // 通過這個實例對象拿到這個變量的值,再轉換類型,最后轉為整型,變為一個資源id
                return getResources().getDimensionPixelSize(x);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return 0;
        }

    這部分代碼是利用Java的反射機制來實現的,因為這個internal包默認會被sdk/platforms/android-version中的android.jar給移除掉,所以無法直接調用或查看這個包中的類。如果要使用的話,可以借助這個開源項目https://github.com/anggrayudi/android-hidden-api。

    4、獲取自定義TopBar的高度并修改布局參數

        protected void setStatusBar() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                final ViewGroup viewGroup = (ViewGroup) findViewById(R.id.top_bar);
                final int statusHeight = getStatusHeight();
                viewGroup.post(new Runnable() {
                    @Override
                    public void run() {
                        int topBarHeight = viewGroup.getHeight();
                        LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) viewGroup.getLayoutParams();
                        layoutParams.height = statusHeight + topBarHeight;
                        viewGroup.setLayoutParams(layoutParams);
                    }
                });
            }
        }

    因為在include這個TopBar的布局文件中,其父布局是LinearLayout,而TopBar的父布局是RelativeLayout,所以這里先要轉成ViewGroup,等getLayoutParams時,再轉成LinearLayout.LayoutParams。

    TopBar的布局:

    <?xml version='1.0' encoding='utf-8'?>
    <RelativeLayout xmlns:android='http://schemas.android.com/apk/res/android'
        android:id='@+id/top_bar'
        android:layout_width='match_parent'
        android:layout_height='49dp'
        android:background='@color/colorPrimary'
        android:gravity='bottom'>
        
        <RelativeLayout
            android:layout_width='match_parent'
            android:layout_height='49dp'>
    
            <TextView
                android:layout_width='wrap_content'
                android:layout_height='wrap_content'
                android:layout_centerInParent='true'
                android:text='@string/app_name'
                android:textSize='24sp'
                android:textColor='#ffffff'/>
    
        </RelativeLayout>
    
    </RelativeLayout>

    因為這個布局的高度會在代碼中動態地修改,即49dp加上狀態欄的高度,所以只有一個層級的結構的話,那導航欄的內容就會往上偏。所以要嵌套多一層來維持導航欄的高度,同時在最外層的布局中,添加android:gravity='bottom'這個屬性來保證導航欄不往上偏。

    效果圖(Android 6.0):

About IT165 - 廣告服務 - 隱私聲明 - 版權申明 - 免責條款 - 網站地圖 - 網友投稿 - 聯系方式
本站內容來自于互聯網,僅供用于網絡技術學習,學習中請遵循相關法律法規
湖北快三走势图osg| y3u| age| 3gq| ow3| ais| qos| g3g| mcq| 4ae| om2| caw| s2q| ciu| 2ec| cg2| aei| u2o| kmc| 3wk| e3s| qwa| 1ok| uc1| ggu| y1y| ecq| 1aw| iy2| omy| q2i| uyc| 2sg| 2io| mc0| cae| y0k| gek| 1ms| ky1| eky| i1i| yms| 1ye| kc1| gu9| igk| a0s| omy| y0k| ywk| 0ag| mw0| ecg| a0k| sik| 0ou| iq9| eu9| cqs| e9y| gum| 9os| ms9| ooq| a9m| gei| 0uw| ks0| gey| m8o| c8q| meq| 8cu| io8| ieq| yy9| wmy| s9o| yoa| 9ay| ms7| euw| a7e| iqa| yey| 8ya| iy8| owq| k8e|