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

    最近在学习EJB 3,对于SSH与EJB3,一直不太明白“即生瑜,何生亮?”,今天无意看到一篇旧文,比较系统的对比了这二种技术架构,转载于此: 原文出处:http://www.51cto.com/sp ...

  2. 安装glue,用glue批量处理图片的步骤

     glue批量处理图片:http://glue.readthedocs.io/en/latest/quickstart.html#and-why-those-css-class-names 首先需要安 ...

  3. 怎样用通用pe工具箱制作U盘启动盘

    U盘启动盘制作过程,随着网络的普及,电脑已经成为我们日常生活中的重要一环,最近自己重装了下电脑系统,无意中发现一个傻瓜式的U盘装系统方法,就把怎么制作通用pe工具箱u盘启动盘的经验拿出来跟大家分享下. ...

  4. 利用Trie树对字符串集合进行排序并计算特征值

    该算法用于将一组乱序的字符串反序列化到一个Trie树中,这个过程即可视为对字符串进行了一次排序. 还可以通过调用 GetFeatureString 将该 Trie 树重新序列化. #include & ...

  5. 昨天做了一个使用javamail发送文件的demo

    记录一下过程. 两种版本第一个demo是纯java文件.一个就可以,是我在网上搜索到的,第二个demo是我在ssh框中中写的jsp页面demo 1.java版本: package com.zq.www ...

  6. mysql utf8mb4与emoji表情

    一 什么是Emoji emoji就是表情符号:词义来自日语(えもじ,e-moji,moji在日语中的含义是字符) 表情符号现已普遍应用于手机短信和网络聊天软件. emoji表情符号,在外国的手机短信里 ...

  7. Ubuntu Linux 环境变量

    2011年09月17日 Ubuntu 下设置adb环境变量 分类: 同Windows一样,Ubuntu Linux系统包含两类环境变量:系统环境变量和用户环境变量.系统环境变量对所有系统用户都有效,用 ...

  8. [OpenCV] 编译源程序 2.4.10 以支持 CUDA

    对源代码进行如下修改: H:\Software\opencv\sources\modules\gpu\src\nvidia\core\NCV.cu中添加 #include <algorithm& ...

  9. JAVA helloworld!

    idea创建java项目 https://jingyan.baidu.com/article/48b558e3f8f6637f39c09a44.html 本地文档运行 java helloworld ...

  10. MYSQL+PHP的学习之路

    MYSQL+PHP 先从MYSQL开始吧 第一步:SQL语句基础 1.书籍 2.网站: 这个网站在线测试和考试http://sqlzoo.net/wiki/SELECT_basics/zh 3.学习过 ...