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)行效果


