首页 > 学院 > 开发设计 > 正文

沉浸式模式

2019-11-06 09:42:36
字体:
来源:转载
供稿:网友

第一次在项目中要用到全屏功能的时候无从下手,然后就是去百度了。百度到的结果都是差不多的。不过直接把代码贴过来的确是可以用的。但是除了知道怎么做之外还想去理解它,因为只有理解了才能举一反三嘛。好在在后来的时候看到了官方的文档,写的非常详细。

–> 我是官方文档 <–

接下来开始正题

… … …

先给出一些名词方便下面的讲解

StatusBar StatusBar

NavigationBar NavigationBar

SystemBar – StatusBar 跟 NavigationBar 的统称


设置全屏主要分为两种方式:

4.0 之前采用的方式4.0 之后新增的方式

4.0 以及之前设置全屏

因为 4.0 之前的系统已经很少了,所以这里就简单的说一下。 有两种方式可以实现全屏:

使用全屏的主题getWindow().addFlag(WindowManager.LayoutParams.FLAG_FULLSCREEN);

这种全屏方式是无法隐藏 NavigationBar 的(如果有 NavigationBar 的话),因为 NavigationBar 是在 4.0 以后才引入的。使用这种方式设置全屏的特点是,离开了 App 后再进入 App 时,依然处于全屏模式,只能清除掉全屏标志位才能退出全屏。


4.1 以及之后设置全屏

4.1 以及之后使用 View 的 setSystemUiVisibility() 来对 SystemBar 进行控制。 任何 View 都可以用来调用这个方法,只要它是可见状态的。

下面先把要涉及到的 flag 分组列举出来(所有的 flag 都是以 SYSTEM_UI_FLAG 作为前缀,所以下面将其省略)。

控制 SystemBar 相关:

FULLSCREENHIDE_NAVIGATIONLOW_PROFILE

布局相关:

LAYOUT_SCREENLAYOUT_HIDE_NAVIGATIONLAYOUT_STABLE

沉浸式相关 (4.4 引入):

IMMERSIVEIMMERSIVE_STICKY

超前提示:

在离开 App 时,比如按了 home / 多任务键 会导致设置的控制 SystemBar 相关的 flag 被清除,而其他设置的 flag 不会受到影响。

FULLSCREEN

虽然写的是 Fullscreen ,但其实只是隐藏 StatusBar。

@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    mDecorView = getWindow().getDecorView();    mDecorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN);    // Google 建议隐藏 StatusBar 时也将 ActionBar 一起隐藏    getActionBar().hide();}1234567891012345678910

这里写图片描述

看图可以得出以下几点:

点击屏幕 StatusBar 不会显示出来从屏幕上边缘往下滑可以让 StatusBar 重新显示点击 home / 多任务键再返回 App 时 StatusBar 重新显示了出来,印证了超前提示里所说的。而且 StatusBar 在显示出来以后不会自动隐藏,这一点跟在 4.1 之前设置的全屏方式不一样,因为设置的 FULLSCREEN flag 已经被清除了,如果想重新隐藏,需要重新设置该 flag。StatusBar 的显示 / 隐藏会使 ImageView 大小发生了变化

为了防止布局大小不会因为 StatusBar 的显示 / 隐藏发生变化,有两种 flag 可供选择:

1.LAYOUT_STABLE

mDecorView.setSystemUiVisibility(        View.SYSTEM_UI_FLAG_FULLSCREEN                 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);123123

这里有一点需要注意:设置多个标志位时要用 | 连接起来,不能多次调用 setSystemUiVisibility。如:

mDecorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN);mDecorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);1212

这样的结果就是只有最后一次设置的 flag 生效,而之前设置的标志位会被清除。也就是说上面的代码中只设置了 LAYOUT_STABLE 而 FULLSCREEN 被清除了。所以如果想清除之前设置的所有 flag ,mDecorView.setSystemUiVisibility(0) 就可以了

这次布局并没有延伸到 StatusBar 底下,所以大小也就不会受到它的影响

2.LAYOUT_FULLSCREEN

mDecorView.setSystemUiVisibility(        View.SYSTEM_UI_FLAG_FULLSCREEN                 | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);123123

可以看到布局已经延伸到了 StatusBar 底部。

HIDE_NAVIGATION

protected void onCreate(Bundle savedInstanceState) {    mDecorView.setSystemUiVisibility(        View.SYSTEM_UI_FLAG_FULLSCREEN            | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);}1234512345

Google 建议隐藏 NavigationBar 的同时将 StatusBar 一起隐藏。

与隐藏 StatusBar 时不同的是,隐藏了 NavigationBar 以后,点击屏幕的任何位置都会导致设置的所有控制 SystemBar 相关的 flag 被清除,所以 SystemBar 重新显示了出来。这里还需要注意的在这种模式下点击屏幕点击事件会被屏蔽,要等到 SystemBar 显示出来以后再次点击,事件才会传递到我们的布局中。

与 LAYOUT_FULLSCREEN 类似的是, LAYOUT_HIDE_NAVIGATION 可以让布局内容延伸到 NavigationBar 的底部。

因为离开 App 后控制 SystemBar 相关的 flag 会被清除,所以可以按需在 onResume() 或者 onWindowFocusChanged() 中重新设置它们。

LOW_PROFILE

protected void onCreate(Bundle savedInstance) {    mDecorView.setSystemUiVisibility(                View.SYSTEM_UI_FLAG_LOW_PROFILE);}12341234

作用是减少 StatusBar 中的图标并使其变暗,将 NavigationBar 中的按钮减弱成 3 个点。 知乎在阅读文章的时候就使用到了这个模式

这里写图片描述

可以看到,在向上滑动内容的时候 SystemBar 的内容被弱化了,这样可以减少其他元素对阅读者的干扰。

设置沉浸式模式(4.4 之后引入)

沉浸式模式是在 4.4 之后才引入的


IMMERSIVE

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             | View.SYSTEM_UI_FLAG_FULLSCREEN            | View.SYSTEM_UI_FLAG_IMMERSIVE);12345671234567

可以看到设置了该 flag 以后,点击屏幕不会让 SystemBar 显示出来。呼出 SystemBar 的方式是在屏幕上边缘向下滑动,在呼出 SystemBar 后,控制 SystemBar 相关的 flag 会被清除。

IMMERSIVE_STICKY

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             | View.SYSTEM_UI_FLAG_FULLSCREEN            | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);12345671234567

跟 IMMERSIVE 不同的是,在该模式下呼出的 SystemBar 会在短暂的显示后重新隐藏。并且在 SystemBar 显示出来的时候点击屏幕中心会立刻让 SystemBar 重新隐藏。所以在模式下呼出 SystemBar 并不会清除控制 SystemBar 相关的 flag。但是离开 App 时控制 SystemBar 相关的 flag 还是会被清除。

所以在回到 App 的时候需要重新设置:

@Overridepublic 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);}}123456789101112123456789101112

监听 SystemBar 的变化

通常情况下我们需要能够控制 SystemBar 的显示与隐藏,这个时候就需要监听 SystemBar 的状态。 通过 OnSystemUiVisibilityChangeListener 就可以对 SystemBar 的状态进行监听。

protected void onCreate(Bundle savedInstance) {    mDecorView.setOnSystemUiVisibilityChangeListener(new OnSystemUiVisibilityChangeListener() {        @Override        public void onSystemUiVisibilityChange(int visibility) {            if (visibility == 0) {            // SystemBar 处于显示状态            } else {            // SystemBar 处于隐藏状态            }        }});12345678910111234567891011

上面的代码展示了如何对 SystemBar 的状态进行监听。 当 SystemBar 的显示状态发生变化时,onSystemUiVisibilityChange() 方法就会被调用。但是有一个例外,设置 IMMERSIVE_STICKY 后将 SystemBar 呼出并不会触发该监听器。

下面具体解释一下 onSystemUiVisibilityChange(int visibility) 方法

onSystemUiVisibilityChange(int visibility) 方法中的 visibility 参数表示的是 LOW_PROFILE、FULLSCREEN 跟HIDE_NAVIGATION 这三个 flag 的值的和。

FULLSCREEN(4)HIDE_NAVIGATION(2)LOW_PROFILE(1)

括号中的数字是它们的值。

为什么 visibility 只是表示这 3 个 flag 的和呢?因为只有这 3 个值是跟控制 SystemBar 相关的。也就是说从visibility 的值就可以只知道我们设置了哪些 flag。比如当 visibility 等于 4 时,说明设置了 FULLSCREEN 这个 flag;如果 visibility 等于 7 则说明 3 种 flag 都设置了。所以当 visibility 为 0 时表示没有设置任何控制 SystemBar 的 flag,也就说明了 SystemBar 当前处于显示状态。

那为什么 visibility 的值会是它们三个的和呢?因为我们在设置 flag 的时候是用 | 将多个 flag 连接在一起的, | 就相当于把它们的值加起来。

下面给出一个 Demo ,功能是点击图片时进入 / 退出全屏

public class MainActivity extends AppCompatActivity {    private static final String TAG = "MainActivity";    @BindView(R.id.image)    ImageView mImage;    View mDecorView;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        ButterKnife.bind(this);        mDecorView = getWindow().getDecorView();        // 让图片铺满屏幕        mDecorView.setSystemUiVisibility(                View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN                        | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);    }    @OnClick(R.id.image)    public void onClick() {        // 只需要处理隐藏 SystemBar 就行了,因为显示 SystemBar 是由系统完成的        hideSystemUI();    }    private void hideSystemUI() {        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                        | View.SYSTEM_UI_FLAG_FULLSCREEN);    }    private void showSystemUI() {        mDecorView.setSystemUiVisibility(                View.SYSTEM_UI_FLAG_LAYOUT_STABLE                        | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION                        | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);    }}12345678910111213141516171819202122232425262728293031323334353637383940414243441234567891011121314151617181920212223242526272829303132333435363738394041424344

这里有一个问题,如果点击稍微快一点的话就会出现只隐藏 StatusBar 而没有隐藏 NavigationBar 的情况。如果有哪个小伙伴知道的话请告知一下。

希望这篇文章能给大家带来一点点帮助。

顶8
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表