随着应用程序的一些深入设计,大家总想要更好的界面和体验,所以有些东西并不能只是知道方法就结束了,是得要去深入研究研究的。通过这个过程我觉得,从应用层面来讲,想实现一个功能很简单,但若想实现的好,就要去了解设计者的设计思路以及提供的方法。而了解设计者想法最直接的途径就是查看文档。当然,了解文档以后还可以再进一步,看看 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. [转载] Linux下多路复用IO接口 epoll select poll 的区别

    原地址:http://bbs.linuxpk.com/thread-43628-1-1.html 废话不多说,一下是本人学习nginx 的时候总结的一些资料,比较乱,但看完后细细揣摩一下应该就弄明白区 ...

  2. Struts2 Convention插件的使用(3)方法前的@Action注解

    package com.hyy.action; import org.apache.struts2.convention.annotation.Action; import com.opensymph ...

  3. SQL server 为多个表添加新的列

    作为一名.NET未入门的程序员,第一次发随笔. 前不久参与写的公司业务程序,目前这个程序的后期维护修复漏洞工作由我来负责.由于业务关系重大,每一步对程序代码的操作都非常谨慎,一旦操作失误,造成的损失和 ...

  4. Android核心分析之十九电话系统之GSMCallTacker

    GSMCallTracker在本质上是一个Handler.<IGNORE_JS_OP> 1.jpg (1.52 KB, 下载次数: 1) 下载附件  保存到相册 2012-3-22 11: ...

  5. JLINK V8 升级5.12E 在MDK5.20不变砖

    转载:只是用了新的固件,步骤跟原子提供的方法 是一模一样的.这边也把步骤写了上来. 使用 SAM-PROG 更新 JLINK 固件一 :安装软件 安装 Install AT91-ISP v1.13.e ...

  6. logback与Log4J的区别

    原文:http://blog.csdn.net/lwzcjd/article/details/5617200 Logback和log4j是非常相似的,如果你对log4j很熟悉,那对logback很快就 ...

  7. Android 代码检查工具SonarQube

    http://blog.csdn.net/rain_butterfly/article/details/42170601 代码检查工具能帮我们检查一些隐藏的bug,代码检查工具中sonar是比较好的一 ...

  8. CentOS下对Apache的中文乱码处理

    # vi /etc/sysconfig/i18nLANG="en_US.UTF-8"SYSFONT="latarcyrheb-sun16" 默认的语言是英文,如 ...

  9. 解决 emulator-5554 disconnected !Cancelling错误

    http://www.xuebuyuan.com/351215.html 使用Android模拟器经常遇到连不上.连一次掉一次等诸多问题(转载+原创) 解决办法一: 在此种情形下,重启ADB即可: 1 ...

  10. Kernel rest_init相关

    Linux系统里,有些进程只有kernel部分的代码,即由一个kernel函数进入,在sched的时候,将其与用户进程同等对待. PID为0的叫swapper或sched进程,对应函数为rest_in ...