随着应用程序的一些深入设计,大家总想要更好的界面和体验,所以有些东西并不能只是知道方法就结束了,是得要去深入研究研究的。通过这个过程我觉得,从应用层面来讲,想实现一个功能很简单,但若想实现的好,就要去了解设计者的设计思路以及提供的方法。而了解设计者想法最直接的途径就是查看文档。当然,了解文档以后还可以再进一步,看看 Android 的源码是怎么实现的,也就是从 Application 层进入到 Framework 层。熟悉 Framework 后就可以配合着 Linux 内核的知识了解 Android 底层的实现了。好了,先把注意放在应用层,毕竟这是最简单的。

System Bars 包括三条 bar:

  • status bar,也就是顶部的一条显示时间、电量、通知等信息的 bar
  • Navigation Bar,底部包含 back 键、home 键以及 recent 键的 bar
  • action bar,程序内顶部的可以添加诸如 search、menu 的 bar

  对 System Bar 的 操作也就是获取高度、状态以及设置显示/隐藏状态,前两者之前写过了,这次就把隐藏这些 bar 写详细点。


淡化系统工具栏

  淡化(dim—不知道这么译合适不)工具栏的效果就是 status bar 和 navigation bar 上的图标都变成一个淡灰色的圆点。这么做的意义就是可以让用户目光的焦点集中在程序要显示的内容上面,避免了屏幕上过多的东西分散用户注意力。

  可能这么说起来感觉这么做没有太大的意义,但实际上用户体验就是各方面一点点的细节积累起来的。有些时候用户在比较几款 APP 的时候都会有很明显的喜欢哪个不喜欢哪个,但让他具体列出来差距在哪里他却列不出来。这其中的原因大多就在这些小细节上,说不出但能感觉的到。而且既然有这个功能,它便有存在的意义,那么就来了解了解它怎么实现的。

  注意这个方法只在4.0版本及以上适用。使用时,应用内容显示的尺寸不会变化,只会把两条 bar 上的图标变淡,一旦触摸 bar 的区域,所有图标就会显现出来,不再消失。

  方法很简单,设置 system flag 为 SYSTEM_UI_FLAG_LOW_PROFILE 即可

getActivity().getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);

  注意一旦触摸 bar 的位置,这个 flag 就会被清空,所以触摸结束后图标也不会淡化了。如果需要继续实现淡化效果,可以用 View.OnSystemUiVisibilityChangeListener 来监听状态变化再做处理。

  如果想通过代码在某些情况下主动清除当前 system ui flag ,可以用:

getActivity().getWindow().getDecorView().setSystemUiVisibility(0);

  看过我之前文章的可以知道,0 代表默认状态,也就是 bar 都正常显示的 flag,即:

public static final int SYSTEM_UI_FLAG_VISIBLE = 0;

隐藏 Status Bar

  其实淡化用的不是很多,而隐藏 Status Bar 倒是比较多。因为可以释放更多的显示空间,可以提供更好的用户体验。

  下面两张图可以看到隐藏 status bar 让程序更直观简洁,看起来更舒服。

  注意,左边的图带有 action bar,如果你不显示 status bar 的时候也要把 action bar 隐藏掉,这是设计界面的建议。
设置方法:

4.0及以下版本:
: 1. 在 manifest 中设置:

<application
...
android:theme="@android:style/Theme.Holo.NoActionBar.Fullscreen" >
...
</application>

这样设置比较简单而且不易出错,因为系统在实例化 mainActivity 前已经拥有要渲染的界面,所以UI转换会比较平滑
: 2. 在代码中用 WindowManager flags 设置

public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// If the Android version is lower than Jellybean, use this call to hide the status bar.
if (Build.VERSION.SDK_INT < 16) {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
setContentView(R.layout.activity_main);
}
...
}

设置完 WindowManager flags 后这个 flag 会一直保留直到用代码清理掉他们。如果已经设定 FLAG_FULLSCREEN,就可以用 FLAG_LAYOUT_IN_SCREEN 设置 activity layout 使用当前可用的屏幕区域,这个 flag 可以防止显示/隐藏 status bar 时界面尺寸变化。

4.1及以上版本:
: 可以用前面提到的 setSystemUiVisibility() 在单独 view 层级上设置 UI 的标志,这些标志在窗口上生效。

View decorView = getWindow().getDecorView();
// Hide the status bar.
int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
// Remember that you should never show the action bar if the
// status bar is hidden, so hide that too if necessary.
ActionBar actionBar = getActionBar();
actionBar.hide();

注意:

  1. 设置的 flag 一旦清空,应用程序需要重新设置 flag 才能隐藏 bar 。添加 listener 做处理即可
  2. 设置 flag 的代码写在不同的地方有不同的效果。比如你在 activity 的 onCreate() 方法里设置隐藏的标志,用户按下 Home 键, status bar 会再度显示,之后再打开应用程序,status bar 会保持显示的状态。如果需要其隐藏掉,需要在 onResume() 或者 onWindowFocusChanged() 方法里设置。
  3. setSystemUiVisibility() 方法只在可见的 view 中设置才有效,比如设置 View.gone 就没有效果
  4. 切换 view 会把当前 view 设置的 flag 清空

将程序内容显示在 Status Bar 的后面
之前的文章遇到过这个问题,还困扰了我半天,后来才发现程序是可以显示在 status bar 的后面的,这样的好处是程序的内容尺寸不会随着 status bar 的显示和隐藏而改变。
实现这个效果只用设置 SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN ,同时用 SYSTEM_UI_FLAG_LAYOUT_STABLE 来保证尺寸不变即可

When you use this approach, it becomes your responsibility to ensure that critical parts of your app’s UI (for example, the built-in controls in a Maps application) don’t end up getting covered by system bars. This could make your app unusable. In most cases you can handle this by adding the android:fitsSystemWindows attribute to your XML layout file, set to true. This adjusts the padding of the parent ViewGroup to leave space for the system windows. This is sufficient for most applications.

In some cases, however, you may need to modify the default padding to get the desired layout for your app. To directly manipulate how your content lays out relative to the system bars (which occupy a space known as the window’s “content insets”), override fitSystemWindows(Rect insets). The fitSystemWindows() method is called by the view hierarchy when the content insets for a window have changed, to allow the window to adjust its content accordingly. By overriding this method you can handle the insets (and hence your app’s layout) however you want.


隐藏 Navigation Bar

  作为设计上的建议,在隐藏掉导航栏的同时,也要把状态栏隐藏掉(当然状态栏隐藏了也要把动作栏也隐藏掉),当然隐藏掉还是保持随时可唤出的,这样可以利用整个屏幕空间,给用户更棒的体验。
  在4.0及以上版本使用 SYSTEM_UI_FLAG_HIDE_NAVIGATION 设置同时隐藏 status bar 和 navigation bar。  

View decorView = getWindow().getDecorView();
// Hide both the navigation bar and the status bar.
// SYSTEM_UI_FLAG_FULLSCREEN is only available on Android 4.1 and higher, but as a general rule, you should design your app to hide the status bar whenever you hide the navigation bar.
int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);

注意事项参考隐藏 status bar 的注意。

当然,既然可以让程序内容显示在 status bar 的后面,那么相同效果也可以在 Navigation bar 上设置。使用 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 和 SYSTEM_UI_FLAG_LAYOUT_STABLE 即可。


使用全屏沉浸模式

  这是4.4版本新加的模式,设置标志为 SYSTEM_UI_FLAG_IMMERSIVE 和 SYSTEM_UI_FLAG_IMMERSIVE_STICKY两种。经常配合着 SYSTEM_UI_FLAG_HIDE_NAVIGATION 和 SYSTEM_UI_FLAG_FULLSCREEN 使用。

(补充:FLAG_IMMERSIVE 要和 FLAG_HIDE_NAVIGATION and FLAG_FULLSCREEN 两者其一一起使用才有效,与前者用为隐藏下方的 bar,与后者用为隐藏上方的 bar)

  这个模式的效果为隐藏掉上下两条 bar,同时你在 bar 的范围内点击事件也不会将其唤出,这为程序的操作提供了很大的便利。你会问,既然点击事件不会唤出 bar,那我要是想用 bar 上的功能怎么办?这个也很简单,手指放在 bar 的区域,如果是 status bar 的区域则手指向下滑动,反之则向上滑动,这样就可以把两条 bar 唤出了。这个操作实际上是把 SYSTEM_UI_FLAG_HIDE_NAVIGATION 和 SYSTEM_UI_FLAG_FULLSCREEN 清掉了,所以才会可见,同时会触发对应的 Listener 。

  前面说了有两种 IMMERSIVE 和 IMMERSIVE_STICKY ,前者是将 bar 唤出后不再消失,后者是将 bar 唤出后几秒就消失,后者不触发 Listener。

  还有一点,设置 FULLSCREEN 会让 status bar 显示的时候背景为半透明,正常状态下 status bar 的背景是黑色的。见下图:
  

图1:正常状态。图2:第一次进入 immersive full-screen mode 时会有提示。

关于 IMMERSIVE 和 IMMERSIVE_STICKY 的选择:

  • 如果是做一个看书、杂志软件或者看新闻软件,建议使用 IMMERSIVE 标志,配合 SYSTEM_UI_FLAG_FULLSCREEN 和 SYSTEM_UI_FLAG_HIDE_NAVIGATION 。因为用户可能会频繁需要用到 UI 按钮,同时在浏览内容的时候不希望被打扰。
  • 如果希望用户体验沉浸模式,那就用 STICKY 标志
  • 如果像视频播放器那样用户交互就很少,就不要用 IMMERSIVE 了,之前写的内容就可以满足需求

  使用 IMMERSIVE 标志时,隐藏的 bar 会一直显示,那么就需要设置一些标志保持软件内容尺寸不变,如SYSTEM_UI_FLAG_HIDE_NAVIGATION 和 SYSTEM_UI_FLAG_LAYOUT_STABLE,同时也要注意 action bar 的隐藏。

// This snippet hides the system bars.
private void hideSystemUI() {
// Set the IMMERSIVE flag.
// Set the content to appear under the system bars so that the content
// doesn't resize when the system bars hide and show.
mDecorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
| View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
| View.SYSTEM_UI_FLAG_IMMERSIVE);
}
// This snippet shows the system bars. It does this by removing all the flags
// except for the ones that make the content appear under the system bars.
private void showSystemUI() {
mDecorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}

  下面是程序窗口收到焦点时设置 IMMERSIVE_STICKY 如下,其实结合前面提到的一些方法,自己组合可以实现很好的效果。

@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
decorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);}
}

对系统工具栏显示变化的响应

  注册一个 View.OnSystemUiVisibilityChangeListener 来使界面同步变化,可以在 onCreate() 方法中添加以下代码:

View decorView = getWindow().getDecorView();
decorView.setOnSystemUiVisibilityChangeListener
(new View.OnSystemUiVisibilityChangeListener() {
@Override
public void onSystemUiVisibilityChange(int visibility) {
// Note that system bars will only be "visible" if none of the
// LOW_PROFILE, HIDE_NAVIGATION, or FULLSCREEN flags are set.
if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
// TODO: The system bars are visible. Make any desired
// adjustments to your UI, such as showing the action bar or
// other navigational controls.
} else {
// TODO: The system bars are NOT visible. Make any desired
// adjustments to your UI, such as hiding the action bar or
// other navigational controls.
}
}
});

以上可能有理解上误差或者我测试中的没发现的错误,如果您看过后发现有哪些问题请留下反馈,谢谢。

[Android] 关于系统工具栏和全屏沉浸模式的更多相关文章

  1. Android UI体验之全屏沉浸式透明状态栏效果

    前言: Android 4.4之后谷歌提供了沉浸式全屏体验, 在沉浸式全屏模式下, 状态栏. 虚拟按键动态隐藏, 应用可以使用完整的屏幕空间, 按照 Google 的说法, 给用户一种 身临其境 的体 ...

  2. Ubuntu下Vim 如何进入全屏编辑模式

    如题:F11进入全屏编辑模式,再按F11则退出全屏编辑模式.

  3. android启动画面隐藏状态栏全屏显示

    1.在根部局给一个id,然后直接设置就行了layout.setSystemUiVisibility(View.INVISIBLE); 状态栏就没有了. 2.如果你只是想改变状态栏颜色的也可以 //5. ...

  4. Android中两种设置全屏的方法

    设置全屏的两种方法: 第一种:在配置文件里面配置: <?xml version="1.0" encoding="utf-8"?><manife ...

  5. Android点击按钮实现全屏的代码

    package com.hsx.test; import java.lang.reflect.Field; import android.app.Activity; import android.os ...

  6. Android中两种设置全屏或者无标题的方法

    在开发中我们经常需要把我们的应用设置为全屏或者不想要title, 这里是有两种方法的,一种是在代码中设置,另一种方法是在配置文件里改: 一.在代码中设置: package jason.tutor; i ...

  7. Android应用----如何让应用全屏

    一般Android的应用启动时都有欢迎界面,类似QQHD启动那样.比较大方绚丽.心动不如行动,有时间自己也来实现类似的效果,嘿嘿.    观察发现QQHD的欢迎界面是全屏的,这个好办.下面就Andro ...

  8. Android开发 - 解决DialogFragment在全屏时View被状态栏遮住的问题

    我的上一篇文章:设置DialogFragment全屏显示 可以设置对话框的内容全屏显示,但是存在在某些机型上顶部的View被状态栏遮住的问题.经过测试,发现了一种解决办法,在DialogFragmen ...

  9. Android开发(十三)——全屏滚动与listview

    Android全屏滚动使用scrollview,其中有需要采用listview进输出的内容,scrollview与listview冲突. 开始的思维是使用一个Scrollview加上一个ListVie ...

随机推荐

  1. Java 网络编程(二)

    以下例开始本文的内容: 例1,需求:上传图片. 客户端: 服务端点. 读取客户端已有的图片数据. 通过socket输出流将数据发给服务端. 读取服务端反馈信息. 关闭. class PicClient ...

  2. 网络处理2-异步POST请求和同步请求

    一.异步POST请求 假如请求路径是http://192.168.1.102:8080/MJServer/login,请求参数有2个: username :母鸡 pwd :123 1.POST请求细节 ...

  3. 2011 ACM/ICPC 成都赛区(为2013/10/20成都现场赛Fighting)

    hdu 4111  Alice and Bob 博弈:http://www.cnblogs.com/XDJjy/p/3350014.html hdu 4112 Break the Chocolate ...

  4. Windows 下 玩转Node.JS

    vs一直是用的比较舒服的IDE,一直期望可以支持Node.JS.终于找到了一个工具 NTVS(Node.JS Tool For VS). 主页:https://nodejstools.codeplex ...

  5. Spring框架学习之第4节

    从ApplicaionContext应用上下文容器中获取bean和从bean工厂容器中有什么区别: 具体案例如下 结论: 1.如果使用上下文ApplicationContext,则配置的bean如果是 ...

  6. linux 操作系统下c语言编程入门

    2)Linux程序设计入门--进程介绍 3)Linux程序设计入门--文件操作 4)Linux程序设计入门--时间概念 5)Linux程序设计入门--信号处理 6)Linux程序设计入门--消息管理  ...

  7. 272. Closest Binary Search Tree Value II

    题目: Given a non-empty binary search tree and a target value, find k values in the BST that are close ...

  8. Android AlarmManager(全局定时器/闹钟)指定时长或以周期形式执行某项操作

    AlarmManager的使用机制有的称呼为全局定时器,有的称呼为闹钟.通过对它的使用,个人觉得叫全局定时器比较合适,其实它的作用和Timer有点相似.都有两种相似的用法:(1)在指定时长后执行某项操 ...

  9. 利用ExtJS导出Excel

    Ext.ns("Msp.Component"); //config = { // fileName : "净值及头寸核对", // exportDate : & ...

  10. AngularJs-ui modal 传参数

    最近开始学习 AnjularJs: 看了两天项目的代码开始动手完成项目中的功能,碰到些问题记录下备忘:方便以后再碰到这样疑惑的coder. 参见 Angular-ui  modal 传递 header ...