Android UI——Material Design ——沉浸式設(shè)計(jì)

Android中的沉浸式設(shè)計(jì)

在Android官方的Material Design指導(dǎo)中,有一種界面的設(shè)計(jì)方案是沉浸式設(shè)計(jì)。所謂的沉浸式設(shè)計(jì),就是只App的界面完全和屏幕和系統(tǒng)融合。而不是帶有系統(tǒng)組件的特點(diǎn)。例如:標(biāo)題欄一般都是有系統(tǒng)的顏色的,比如黑色狀態(tài)欄 淺灰色狀態(tài)欄 。導(dǎo)航欄也有系統(tǒng)的顏色。沉浸式就是通過(guò)修改一些組件的風(fēng)格和效果。使得和當(dāng)前運(yùn)行的App一致,達(dá)到整個(gè)界面都是相同的設(shè)計(jì)元素。
沉浸式個(gè)人認(rèn)為來(lái)說(shuō)是一個(gè)設(shè)計(jì)的思想。但是對(duì)于實(shí)現(xiàn)的方案有不同的實(shí)現(xiàn)。各個(gè)大廠也都有自己的實(shí)現(xiàn)方案。這里我總結(jié)個(gè)人的沉浸式的實(shí)現(xiàn)方式。也是目前用在項(xiàng)目中的沉浸式設(shè)計(jì)方案

由于Android 有很多版本 各個(gè)版本的效果差異比較明顯,所以在我們實(shí)現(xiàn)沉浸式的時(shí)候。要考慮兼容問(wèn)題。針對(duì)不同版本有不同的實(shí)現(xiàn)方案。
官方的沉浸式Translucent:就是讓整個(gè)App沉浸在屏幕里面,有點(diǎn)類似全屏的效果。

標(biāo)題欄沉浸式設(shè)計(jì)

針對(duì)5.0以上的API

1 我們可以通過(guò)設(shè)置主題

<!-- Application theme. -->
        <style name="AppTheme" parent="AppBaseTheme">
        <!-- All customizations that are NOT specific to a particular API-level can go here. -->
        <item name="android:textColor">@color/mytextcolor</item>
        <item name="colorPrimary">@color/colorPrimary_pink</item>
        <item name="colorPrimaryDark">@color/colorPrimary_pinkDark</item>
    <!--         <item name="android:windowBackground">@color/background</item> -->
    <!--         <item name="colorAccent">#906292</item> -->
        </style>

2 可以通過(guò)設(shè)置樣式屬性來(lái)解決??梢栽O(shè)置style.xml

<item name="android:statusBarColor">@color/system_bottom_nav_color</item>

3 通過(guò)代碼設(shè)置

getWindow().setStatusBarColor(getResources().getColor(R.color.material_blue_grey_800));
        (注意:要在setContentView方法之前設(shè)置)

針對(duì)4,4API

由于在4.4中新增了API,可以設(shè)置狀態(tài)欄為透明的
1 可以在屬性樣式里面解決(這種方式不推薦,會(huì)出現(xiàn)兼容性的問(wèn)題)

<item name="android:windowTranslucentStatus">true</item>

2 可以在代碼里解決

getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        setContentView(R.layout.activity_main);

在這種情況下,會(huì)出現(xiàn)APP的內(nèi)容被頂?shù)搅松厦妫瑺顟B(tài)欄會(huì)遮擋界面
解決方式如下:
1 給ToolBar設(shè)置android:fitsSystemWindows=true
這個(gè)屬性的作用是:在設(shè)置布局時(shí),是否考慮當(dāng)前系統(tǒng)窗口的布局,如果設(shè)置為true就會(huì)調(diào)整整個(gè)系統(tǒng)窗口布局包括狀態(tài)欄的view以適應(yīng)你的布局。
但是這種情況下,當(dāng)里面有ScrollView并且里面有Edittext的時(shí)候,就會(huì)出現(xiàn)軟鍵盤彈起后會(huì)把toolbar拉取下來(lái)的bug
2 這里我們推薦的做法是,在布局最外層容器設(shè)置android:fitsSystemWindows=true,可以達(dá)到狀態(tài)欄不會(huì)被輸入法影響產(chǎn)生Bug

步驟:

* 1.在最外層容器設(shè)置android:fitsSystemWindows="true"
* 2.不要給Toolbar設(shè)置android:fitsSystemWindows="true"
    * 2.直接將最外層容器(也可以修改-android:windowBackground顏色)設(shè)置成狀態(tài)欄想要的顏色
    * 3.下面剩下的布局再包裹一層正常的背景顏色。

3 修改ToolBar的高度
1.不要給Toolbar設(shè)置android:fitsSystemWindows="true"
2.需要知道狀態(tài)欄的高度是多少?去源碼里面找找

                <!-- Height of the status bar -->
                <dimen name="status_bar_height">24dp</dimen>
                <!-- Height of the bottom navigation / system bar. -->
                <dimen name="navigation_bar_height">48dp</dimen>
                反射手機(jī)運(yùn)行的類:android.R.dimen.status_bar_height.
3.修改Toolbar的PaddingTop(因?yàn)榧兇庠黾觮oolbar的高度會(huì)遮擋toobar里面的一些內(nèi)容)
                toolbar.setPadding(
                    toolbar.getPaddingLeft(),
                    toolbar.getPaddingTop()+getStatusBarHeight(this), 
                    toolbar.getPaddingRight(),
                    toolbar.getPaddingBottom());

4.或者可以設(shè)置toolbar的高度(不推薦)

底部虛擬導(dǎo)航欄設(shè)計(jì)

5.x 調(diào)用提供的API實(shí)現(xiàn)

1 屬性解決

navigationBarColor

2 代碼

getWindow().setNavigationBarColor()

4.4版本 用一些特殊手段。設(shè)置底部虛擬導(dǎo)航欄為透明

步驟:
1)在布局底部添加一個(gè)高度為0.1dp的view
2)動(dòng)態(tài)設(shè)置底部View的高度為虛擬導(dǎo)航欄的高度
View nav = findViewById(R.id.nav);
LayoutParams p = nav.getLayoutParams();
p.height += getNavigationBarHeight(this);
nav.setLayoutParams(p);

具體案例

我們需要?jiǎng)?chuàng)建一個(gè)BaseTranslucentActivity作為父Activity

/**
 * @author wxblack-mac
 * @DESCRIBE:沉浸式狀態(tài)欄的父Activity
 * @DATE 2019/3/6 10:33
 * GOOD LUCK
 */
@SuppressLint("Registered")
public class BaseTranslucentActivity extends AppCompatActivity {

    private Toolbar toolbar;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //判斷系統(tǒng)版本
        //[4.4,5.0) 手動(dòng)實(shí)現(xiàn)沉浸式狀態(tài)欄和導(dǎo)航欄透明
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
                && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            //狀態(tài)欄透明
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            //導(dǎo)航欄透明
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
        }
    }

    public void setOrChangeTranslucentColor(Toolbar toolbar, View bottomNavigationBar, int translucentPrimaryColor) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
                && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            if (toolbar != null) {
                //1.先設(shè)置toolbar的高度
                ViewGroup.LayoutParams params = toolbar.getLayoutParams();
                int statusBarHeight = getStatusBarHeight(this);
                params.height += statusBarHeight;
                toolbar.setLayoutParams(params);
                //2.設(shè)置paddingTop,以達(dá)到狀態(tài)欄不遮擋toolbar的內(nèi)容。
                toolbar.setPadding(
                        toolbar.getPaddingLeft(),
                        toolbar.getPaddingTop() + getStatusBarHeight(this),
                        toolbar.getPaddingRight(),
                        toolbar.getPaddingBottom());
                //設(shè)置頂部的顏色
                toolbar.setBackgroundColor(translucentPrimaryColor);
            }
            if (bottomNavigationBar != null) {
                //解決低版本4.4+的虛擬導(dǎo)航欄的
                if (hasNavigationBarShow(getWindowManager())) {
                    ViewGroup.LayoutParams p = bottomNavigationBar.getLayoutParams();
                    p.height += getNavigationBarHeight(this);
                    bottomNavigationBar.setLayoutParams(p);
                    //設(shè)置底部導(dǎo)航欄的顏色
                    bottomNavigationBar.setBackgroundColor(translucentPrimaryColor);
                }
            }
        }else if(android.os.Build.VERSION.SDK_INT>=android.os.Build.VERSION_CODES.LOLLIPOP){
            getWindow().setNavigationBarColor(translucentPrimaryColor);
            getWindow().setStatusBarColor(translucentPrimaryColor);
        }else{
            //<4.4的,不做處理
        }
    }


    private int getNavigationBarHeight(Context context) {
        return getSystemComponentDimen(this, "navigation_bar_height");
    }

    /**
     * 獲取狀態(tài)欄的高度
     *
     * @param context
     * @return
     */
    private int getStatusBarHeight(Context context) {
        // 反射手機(jī)運(yùn)行的類:android.R.dimen.status_bar_height.
        return getSystemComponentDimen(this, "status_bar_height");
    }

    private static int getSystemComponentDimen(Context context, String dimenName) {
        // 反射手機(jī)運(yùn)行的類:android.R.dimen.status_bar_height.
        int statusHeight = -1;
        try {
            Class<?> clazz = Class.forName("com.android.internal.R$dimen");
            Object object = clazz.newInstance();
            String heightStr = clazz.getField(dimenName).get(object).toString();
            int height = Integer.parseInt(heightStr);
            //dp--->px
            statusHeight = context.getResources().getDimensionPixelSize(height);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return statusHeight;
    }


    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
    private static boolean hasNavigationBarShow(WindowManager wm) {
        Display display = wm.getDefaultDisplay();
        DisplayMetrics outMetrics = new DisplayMetrics();
        //獲取整個(gè)屏幕的高度
        display.getRealMetrics(outMetrics);
        int heightPixels = outMetrics.heightPixels;
        int widthPixels = outMetrics.widthPixels;
        //獲取內(nèi)容展示部分的高度
        outMetrics = new DisplayMetrics();
        display.getMetrics(outMetrics);
        int heightPixels2 = outMetrics.heightPixels;
        int widthPixels2 = outMetrics.widthPixels;
        int w = widthPixels - widthPixels2;
        int h = heightPixels - heightPixels2;
        System.out.println("~~~~~~~~~~~~~~~~h:" + h);
        return w > 0 || h > 0;//豎屏和橫屏兩種情況。
    }
}

在子Activity調(diào)用的時(shí)候 MainActivity

public class MainActivity extends BaseTranslucentActivity {

    private Toolbar toolbar;
    private View navigationView;

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        toolbar = ((Toolbar) findViewById(R.id.toolbar));
        navigationView = findViewById(R.id.nav);
        setOrChangeTranslucentColor(toolbar, navigationView, getResources().getColor(R.color.colorPrimary));
    }
}

各個(gè)版本運(yùn)行效果

Android 4.4
Android 5.0
Android 6.0
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容