文章目录
一、防止布局被刘海屏遮挡的处理方式
现在手机上会有很多种刘海屏、水滴屏等状态。有时候不做处理的话布局会被刘海屏遮挡。这里需要用到android:fitsSystemWindows="true"
属性。如果无效的话,尝试把布局设置为透明即可。
二、改变Android状态栏的颜色
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public static void setStatusBarColor(int statusColor, Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = activity.getWindow();
//取消设置Window半透明的Flag
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//添加Flag把状态栏设为可绘制模式
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
//设置状态栏为透明
window.setStatusBarColor(Color.TRANSPARENT);
//如果想要修改标题栏文字可以在这里进行修改
// setAndroidNativeLightStatusBar(activity, true);//字体修改为深色
}
}
public static void setAndroidNativeLightStatusBar(@NonNull Activity activity, boolean dark) {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
View decor = activity.getWindow().getDecorView();
if (dark) {
decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
} else {
decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
}
}
} catch (Exception ignore) {
}
}
三、fitsSystemWindows与布局的关系
这里的代码解释有问题,暂时删除,具体可以直接使用上述代码或者<style>
的方式实现沉浸式。在郭霖的帖子里面写的只需要更改状态栏颜色为透明的话会出现一些其他问题,比较好的方式是,也添加这行代码activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
。该代码加上状态栏透明的代码效果和下文的<style>
中设置沉浸式效果一样。具体差异未深究
这里有两种情况;
- 假设容器布局也只是传统的布局
LinearLayout
布局
如果什么都不做的话。只是使用fitsSystemWindows
属性并不会使布局延伸到状态栏上,这里需要配合上面的代码进行处理。但是并不是所有的组件都可以使用fitsSystemWindows
来进行修饰。例如View
,而非ViewGroup
。例如在TextView
、ImageView
上面使用就不会有效果。但是在ViewGroup
上面使用就会有效果。 - 假设容器布局是
CoordinatorLayout
、CollapsingToolbarLayout
、DrawerLayout
这些会有一些另外的情况,这时候不需要使用上面的java代码也能实现沉浸式处理,参考以下链接,
https://guolin.blog.csdn.net/article/details/123023395。
另外需要注意的是如果要开启沉浸式状态栏,还要设置style样式,代码设置则不用如此如下:<style name="Theme.DesignTest" parent="Theme.MaterialComponents.DayNight.DarkActionBar"> ... <!-- Customize your theme here. --> <item name="android:windowTranslucentStatus">true</item><!--设置沉浸式状态栏--> </style>
- 假如想给状态栏架上遮罩层的话,可以使用
<FrameLayout>
、<LinearLayout>
的不会延伸的特性,例如下文的示例代码,该代码并不需要显示声明高度
四、一个常见的例子
结合上述代码,这里实现一种常见的效果
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#F4F5F7">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/js_bg_result_header"
app:layout_constraintTop_toTopOf="parent"/>
<FrameLayout
android:id="@+id/fl_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/sq_black_alpha_30"
android:fitsSystemWindows="true"
app:layout_constraintTop_toTopOf="parent"
tools:layout_height="25dp" />
<TextView
android:id="@+id/tv_back"
style="@style/Sqmedium_18_black"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="@dimen/sq_dp_8"
android:fitsSystemWindows="true"
android:gravity="center_vertical"
android:minHeight="@dimen/sq_dp_44"
android:paddingStart="@dimen/sq_dp_12"
android:text="@string/sq_feed_back"
android:textColor="@color/sq_black_alpha_80"
android:textSize="@dimen/sq_sp_16"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/fl_status"
tools:ignore="RtlSymmetry" />
</androidx.constraintlayout.widget.ConstraintLayout>
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
setupWindow(this);
super.onCreate(savedInstanceState);
}
private void setupWindow(Activity activity) {
if (activity != null && activity.getWindow() != null) {
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
}
}
}
五、setDecorFitsSystemWindows
该函数用于表示内容是否超出状态栏和底部操作栏,false为超过
WindowCompat.setDecorFitsSystemWindows(window, false)
六、enableEdgeToEdge()
使用enableEdgeToEdge()
也可以做到沉浸式,源自依赖
import androidx.activity.enableEdgeToEdge
。
androidx.activity:activity:1.8.1@aar
如果不能升级的话使用google的com.google.android.material
也是可以的
EdgeToEdgeUtils.applyEdgeToEdge()
七、Fragment
正常来说Fragment
也可以使用上述方案实现沉浸式,倘若布局无法出现,可以尝试以下方案
需要注意的是该方案在Fragment
中无法使用FrameLayout
的特性,可以自己设置高度,或者使用第三方库
八、DialogFragment
如果是对话框的话,那么需要在样式里面去修改,毕竟Dialog和Activity不是一个window。
<style name="base_dialog_style" parent="android:Theme.Dialog">
....
<item name="android:windowTranslucentStatus">true</item><!--设置沉浸式状态栏-->
</style>
九、Compose
Android Jetpack Compose 沉浸式状态栏的实现
如果不使用上述链接的解决方式的话,可以使用第六条的解决方案applyEdgeToEdge()
。但是该情况下,内容会延伸到状态栏下面,如果需要做到背景延伸,但是内容在状态栏下面,可以使用Modifider..systemBarsPadding()
进行高度填充。
可使用方式具体可参考accompanist,这里面不止提供了accompanist的代码还提供了在androidX中可以使用哪些代码
十、参考链接
- 沉浸式兼容库:
更新较新:https://github.com/gyf-dev/ImmersionBar
长时间未更新:https://github.com/laobie/statusbarutil - WindowInsetsControllerCompat使用,新方式实现状态栏、导航栏、键盘控制
- Android开发 WindowInsetsController 窗口控制器
- Android 沉浸式状态栏和全面屏遇到刘海屏
- Android Detail:Window 篇——WindowInsets 与 fitsSystemBar
- Android开发 WindowInsetsController 窗口控制器
- 再学一遍android:fitsSystemWindows属性
- ANDROID沉浸式状态栏、FITSSYSTEMWINDOWS、标题栏折叠
- systemuicontroller(Compose版的状态栏控制)
- 在应用中全屏显示内容
- android 软键盘动画
- Android软键盘遮挡/动画最佳解决方案
- WindowInsetsControllerCompat使用,新方式实现状态栏、导航栏、键盘控制