前言
手机的屏幕越来越大,为了能够展示更多的界面元素现在兴起了沉浸式的界面,也就是整个屏幕都可以展示用户素材。通常的手机界面都有StatusBar状态栏在顶部,状态栏下面的ActionBar负责展示标题回退按钮以及操作菜单,中间部分是用户内容区,最下面则展示了NavigationBar,也就是用户导航栏,通常有Back、Home和Menu这几个键位。现在来学习一下如何操作这些系统提供的界面。
透明状态栏
状态栏现在常见的用法就是透明状态栏,当然也可以自己设置其他颜色的状态栏背景,但是这些都是有版本要求的。只有在版本号大于19才可以设置透明状态栏19以下版本无法修改状态栏颜色。在19以上需要使用translucentStatus属性,但是到了21版本,translucent变成半透明也就是有一点灰色的背景,为了达到透明效果需要设置statusBarColor为transparent。设置Theme的XML文件如下:
首先是values.xml只是供19以下的Android使用,这个不会有什么效果。
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="AppTheme.TranslucentStatus">
</style>
values-v19.xml供19以上版本使用的样式:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme.TranslucentStatus">
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
</style>
</resources>
values-v21.xml供21以上版本使用的样式:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme.TranslucentStatus">
// 21以上不再设置translucentStatus,直接设置statusBarColor就行了
<item name="android:windowTranslucentStatus">false</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:windowTranslucentNavigation">true</item>
</style>
</resources>
在N5上测试windowTranslucentStatus和windowTranslucentNavigation必须同时设置否则就不会展示透明的状态栏
设置完这些就可以看到状态栏在19以上变成透明的,但是如果你设置的背景是白色的,在StatusBar上的文字和图标也是白色的,这时后可以设置windowLightStatusBar属性将文字调成黑色展示,但是这个属性目前只在23以上支持,MiUI和FlyMe可以适配,其他的手机还要看具体的效果。
values-v23.xml提供23以上版本使用的样式:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme.TranslucentStatus">
<item name="android:windowTranslucentStatus">false</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:windowTranslucentNavigation">true</item>
<item name="android:windowLightStatusBar">true</item>
</style>
</resources>
小米和魅族的适配代码如下:
public static void setStatusBarLight(Activity activity) {
String manufacturer = Build.MANUFACTURER.toLowerCase();
// 首先获取当前设备制造商,而且版本高于23
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (manufacturer.contains("xiaomi")) {
setXiaomiStatusBarLightMode(activity);
} else if (manufacturer.contains("meizu")) {
setMeizuStatusBarLightMode(activity);
}
}
}
/**
* MIUI
* <p>
* {@inheritDoc https://dev.mi.com/doc/p=4769/index.html}
*
* @param activity 引用的Activity
*/
private static void setXiaomiStatusBarLightMode(Activity activity) {
Class<? extends Window> clazz = activity.getWindow().getClass();
try {
@SuppressLint("PrivateApi")
Class<?> layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
int darkModeFlag = field.getInt(layoutParams);
if (darkModeFlag == 0) darkModeFlag = 16;
Method extraFlagField = clazz.getMethod("addExtraFlags", int.class);
extraFlagField.invoke(activity.getWindow(), darkModeFlag);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* flyme4+才可修改
* {@inheritDoc http://open-wiki.flyme.cn/index.php?title=Flyme%E7%B3%BB%E7%BB%9FAPI}
*
* @param activity 引用的Activity
*/
private static void setMeizuStatusBarLightMode(Activity activity) {
Window window = activity.getWindow();
if (window != null) {
try {
WindowManager.LayoutParams lp = window.getAttributes();
Field darkFlag = WindowManager.LayoutParams.class
.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");
Field meizuFlags = WindowManager.LayoutParams.class
.getDeclaredField("meizuFlags");
darkFlag.setAccessible(true);
meizuFlags.setAccessible(true);
int bit = darkFlag.getInt(null);
int value = meizuFlags.getInt(lp);
value |= bit;
meizuFlags.setInt(lp, value);
window.setAttributes(lp);
} catch (Exception e) {
e.printStackTrace();
}
}
ActionBar
前面已经设置好状态栏是透明色,但是ActionBar还没有设置,如何将ActionBar也设置为透明呢?其实也是有一个actionBarStyle的属性,可以在里面设置状态栏的背景为透明,同时也要设置 windowActionBarOverlay状态栏处于悬浮状态,否则ActionBar会在状态栏和内容之间形成一个空白。这样设置之后在低版本上还会看到ActionBar底部有一条黑色的线,设置windowContentOverlay黑色线就会消失。
<style name="OverlayActionBar" parent="AppTheme.TranslucentStatus">
<item name="android:actionBarStyle">@style/ActionBarStyle</item>
<item name="actionBarStyle">@style/ActionBarStyle</item>
<item name="android:windowContentOverlay">@null</item>
</style>
<style name="ActionBarStyle" parent="@style/Widget.AppCompat.Light.ActionBar.Solid.Inverse">
<item name="android:background">@android:color/transparent</item>
<item name="background">@android:color/transparent</item>
<item name="android:windowActionBarOverlay">true</item>
<item name="windowActionBarOverlay">true</item>
</style>
现在已经不推荐再使用ActionBar了,而是使用Toolbar控件取代原有的对象,使用Toolbar的时候需要注意Activity的Theme必须设置为NoActionBar。
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
然后在setContentView的xml里定义ToolBar对象,运行会发现Toobar的顶部和StatusBar顶部在一起,设置contentView的fitSystemWindows就可以为Toolbar父控件添加StatusBar高度的padding。
public class IndexActivity extends AppCompatActivity {
private Toolbar mToolbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_index);
mToolbar = (Toolbar) findViewById(R.id.tool_bar);
mToolbar.setTitle(R.string.app_name);
setSupportActionBar(mToolbar);
}
}
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/timg"
android:fitsSystemWindows="true"
tools:context="com.example.image.IndexActivity">
<android.support.v7.widget.Toolbar
android:id="@+id/tool_bar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize">
</android.support.v7.widget.Toolbar>
</FrameLayout>
其他的设置不变,可以发现Toolbar也变成了透明背景。
NavigationBar
导航栏除了前面设置windowTranslucentNavigation设置为半透明色,4.0以上版本可以使用setSystemUiVisibility在代码中动态设置展示还是隐藏导航栏。现在可以把Activity设置为没有透明顶部的普通Theme,通过代码设置状态栏和NavigationBar的展示和隐藏。
int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_FULLSCREEN |
View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
getWindow().getDecorView().setSystemUiVisibility(uiOptions);