android沉浸状态栏+导航栏(小白条) JAVA版小白教程 (基于安卓官方教程)
沉浸状态栏+导航栏(小白条)是基本操作,但是网上的很多教程都是错误的...,安卓官方的教程对小白很不友好,所以记录下我的实现过程供大家参考。
概述
前置知识
状态栏是屏幕顶部显示时间、通知图标等等的地方
导航栏就是屏幕下方用于提供返回,返回桌面,进入多任务界面的的三个按键或着小白条
状态栏和导航栏统称为系统栏
文章分为两部分:
-
启用沉浸状态栏+导航栏
沉浸系统栏的实质是:将UI内容铺满整个屏幕,应用内容显示在系统栏下方,具体看下图:
(默认情况下,应用内容的绘制范围从顶部状态栏下方开始,延伸至底部导航栏上方。)
-
处理视觉/操作冲突
因为UI内容铺满整个屏幕,因此处在屏幕底部/顶部的某些组件必然被系统栏遮盖,导致用户无法看见或操作,比如下图。因此需要进行处理
启用沉浸状态栏+导航栏
1. 请求进行全屏布局
第一步是让系统将我们应用布局扩展至系统栏后方。
需要使用的setSystemUiVisibility()设置两个标记,这两个标记可以告知系统应全屏放置应用的视图,就好像导航栏和状态栏不存在一样。
标记的含义和用法看代码吧,设置代码如下:
public class LoginActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.constraint_login); /********************设置开始*****************************/ Window window = getWindow(); // 请求进行全屏布局 // SYSTEM_UI_FLAG_LAYOUT_STABLE //*** Tells the system that the window wishes the content to //*** be laid out at the most extreme scenario. See the docs for //*** more information on the specifics //SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION //*** Tells the system that the window wishes the content to //*** be laid out as if the navigation bar was hidden window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); /********************设置结束*****************************/ } }
设置完毕后,应该可以看到应用的内容出现在系统栏的后面:
注意:使用 setSystemUiVisibility() 设置其他标记时,应注意这些其他标记不会覆盖上述标记。 后面会用到
扩展:
对于其他全屏事件,您还可以设置 SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN,以便将状态栏移到后侧。
如果您使用的是自动处理状态栏的视图类(如 CoordinatorLayout 或 DrawerLayout),SYSTEM_UI_FLAG_LAYOUT_STABLE 和 SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 标记可能已设置。
2. 更改系统栏颜色
现在应用布局已经拓展至全屏范围,因此需要同步更改一下系统栏的颜色,以便看清其后面的应用内容。
Android 10以上
在 Android 10 上,我们只需要将系统栏颜色设为完全透明即可:
1. 利用java代码
public class LoginActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.constraint_login); Window window = getWindow(); // 请求进行全屏布局 window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); /********************设置开始*****************************/ // 沉浸状态栏(给任务栏上透明的色)(Android 10 上,只需要将系统栏颜色设为完全透明即可:) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { window.setStatusBarColor(Color.TRANSPARENT); } // 沉浸导航栏(设置透明色) window.setNavigationBarColor(Color.TRANSPARENT); /********************设置结束*****************************/ } }
2. 利用xml
<!-- values-v29/themes.xml --> <style name="Theme.MyApp"> <item name="android:navigationBarColor"> @android:color/transparent </item> <!-- Optional, if drawing behind the status bar too --> <item name="android:statusBarColor"> @android:color/transparent </item> </style>
Android 9 及更早版本(没适配)
以下是原文:
如果您决定在 Android 10 以下的设备上实现全面屏应用,则应将系统栏颜色设置为半透明,从而确保其内容可见。比如针对深色主题的系统栏,可以先试试使用 70% 不透明度的黑色进行遮盖:
<!-- values/themes.xml --> <style name="Theme.MyApp"> <item name="android:navigationBarColor"> #B3FFFFFF </item> </style> <!-- values-night/themes.xml --> <style name="Theme.MyApp"> <item name="android:navigationBarColor"> #B3000000 </item> </style>
您可能需要根据系统栏后面显示的内容来调整遮盖的不透明度。对于浅色主题,可以试试使用半透明浅色遮盖 (如 #B3FFFFFF)。
设置完后会有几个小问题,下面一一解决
更改状态栏字体颜色问题
如果系统是白天模式,状态栏组件颜色默认是白色,而状态栏文字颜色默认是浅色,因此需要手动将状态栏文字颜色改成深色。
注意:安卓版本6.0+才能设置
很明显我们需要做两件事情:
-
获取程序是不是夜间模式
(不理解,直接看代码即可)
通过方法getApplicationContext().getResources().getConfiguration().uiMode;
即可获取程序的模式
再和Configuration.UI_MODE_NIGHT_MASK)
取并,
就可以通过Configuration.UI_MODE_NIGHT_YES
判断是否为夜间模式 -
根据模式的不同,修改状态栏颜色
修改状态栏颜色需要使用的setSystemUiVisibility()设置标记
-
View.SYSTEM_UI_FLAG_VISIBLE
状态栏字体设置为白色
-
View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
状态栏字体设置为黑色
之前说过
注意:使用 setSystemUiVisibility() 设置其他标记时,应注意这些其他标记不会覆盖上述标记。
因此需要将标记此次标记和之请求进行全屏布局
的标记合并,代码如下:
public class LoginActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.constraint_login); Window window = getWindow(); /********************设置开始*****************************/ // 请求进行全屏布局+更改状态栏字体颜色 // 获取程序是不是夜间模式 int uiMode = getApplicationContext().getResources().getConfiguration().uiMode; if ((uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES){ // SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION and SYSTEM_UI_FLAG_LAYOUT_STABLE请求进行全屏布局 // SYSTEM_UI_FLAG_VISIBLE进行更改状态栏字体颜色 window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE|View.SYSTEM_UI_FLAG_VISIBLE);//白色 } else { window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE|View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);//黑色 } /********************设置结束*****************************/ // 让内容显示在系统栏的后面,也就是显示在状态栏和导航栏的后面 WindowCompat.setDecorFitsSystemWindows(window, true); // 沉浸状态栏(给任务栏上透明的色)(Android 10 上,只需要将系统栏颜色设为完全透明即可:) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { window.setStatusBarColor(Color.TRANSPARENT); } // 沉浸导航栏(设置透明色) window.setNavigationBarColor(Color.TRANSPARENT); } }
解决半透明遮盖(禁用系统栏视觉保护)
当应用声明 targetSdkVersion 为 29 以上时,系统可能会在按钮后方提供半透明遮盖,确保用户始终可以看到系统栏的内容,显示如下:
如果应用针对的是 SDK 28 或更低版本,则系统不会显示遮盖,而是提供透明的导航栏。
解决方法:
1. java代码
将下述代码放入上面代码下面即可,代码如下:
//在安卓10以上禁用系统栏视觉保护。 // 当设置了 导航栏 栏背景为透明时,NavigationBarContrastEnforced 如果为true,则系统会自动绘制一个半透明背景 // 状态栏的StatusBarContrast 效果同理,但是值默认为false,因此不用设置 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { window.setNavigationBarContrastEnforced(false); }
2. 在主题中
将 android:enforceNavigationBarContrast 和/或 android:enforceStatusBarContrast 的值设置为 false即可。
整体代码如下
启用沉浸状态栏+导航栏的整体代码如下(我是纯java实现):
public class LoginActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.constraint_login); Window window = getWindow(); // 请求进行全屏布局+更改状态栏字体颜色 // 获取程序是不是夜间模式 int uiMode = getApplicationContext().getResources().getConfiguration().uiMode; if ((uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES){ // SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION and SYSTEM_UI_FLAG_LAYOUT_STABLE请求进行全屏布局 // SYSTEM_UI_FLAG_VISIBLE进行更改状态栏字体颜色 window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE|View.SYSTEM_UI_FLAG_VISIBLE);//白色 } else { window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE|View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);//黑色 } // 让内容显示在系统栏的后面,也就是显示在状态栏和导航栏的后面 WindowCompat.setDecorFitsSystemWindows(window, true); // 沉浸状态栏(给任务栏上透明的色)(Android 10 上,只需要将系统栏颜色设为完全透明即可:) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { window.setStatusBarColor(Color.TRANSPARENT); } // 沉浸导航栏(设置透明色) window.setNavigationBarColor(Color.TRANSPARENT); // 在安卓10以上禁用系统栏视觉保护。 // 当设置了 导航栏 栏背景为透明时,NavigationBarContrastEnforced 如果为true,则系统会自动绘制一个半透明背景 // 状态栏的StatusBarContrast 效果同理,但是值默认为false,因此不用设置 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { window.setNavigationBarContrastEnforced(false); } } }
处理视觉/操作冲突
因为UI内容铺满整个屏幕,因此处在屏幕底部/顶部的某些组件必然被系统栏遮盖,导致用户无法看见或操作,比如下图。
补:insets 区域
Insets 区域可以理解为Android系统占用的区域,比如下图的 左/右侧的后退操作区域宽 40dp,下方的主屏操作区域高 60dp:
在 Android 上,Insets 区域由 WindowInsets 类表示,在 AndroidX 中则使用 WindowInsetsCompat。
解决办法就是
-
获取Android系统占用的区域(被称为insets 区域)的大小
通过方法:getSystemWindowInsets()
,即可获取系统的insets的值 -
将被覆盖的组件Padding值设为该insets区域对应值大小,即可把视图从屏幕边缘向内移动到一个合适的位置,如下图。
就是利用java代码设置padding值,具体看代码吧
代码:
public class LoginActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.constraint_login); Window window = getWindow(); // 启用沉浸状态栏+导航栏(上面的代码) // ............... /********************设置开始*****************************/ // 处理视觉冲突 //对最底部布局设置底部Padding LinearLayout linearBottom=findViewById(R.id.linear_bottom); linearBottom.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() { @NonNull @Override public WindowInsets onApplyWindowInsets(@NonNull View v, @NonNull WindowInsets insets) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { v.setPadding(v.getPaddingLeft(),v.getPaddingTop(),v.getPaddingRight(),insets.getSystemWindowInsets().bottom); } return insets; } }); //对最顶部布局设置顶部Padding LinearLayout linear_top=findViewById(R.id.linear_top); linear_top.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() { @NonNull @Override public WindowInsets onApplyWindowInsets(@NonNull View v, @NonNull WindowInsets insets) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { v.setPadding(v.getPaddingLeft(),insets.getSystemWindowInsets().top,v.getPaddingRight(),v.getPaddingBottom()); } return insets; } }); /********************设置结束*****************************/ } }
本文作者:kingwzun
本文链接:https://www.cnblogs.com/kingwz/p/17300036.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步