Skip to content

Commit 9fd2c8f

Browse files
committed
优化沉浸式状态栏和导航栏的适配方式
1 parent b9193ff commit 9fd2c8f

8 files changed

Lines changed: 208 additions & 146 deletions

File tree

‎app/src/main/java/com/hjq/demo/app/AppActivity.java‎

Lines changed: 94 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
package com.hjq.demo.app;
22

33
import android.content.Intent;
4-
import android.graphics.Insets;
54
import android.view.View;
6-
import android.view.View.OnApplyWindowInsetsListener;
7-
import android.view.WindowInsets;
85
import androidx.annotation.NonNull;
96
import androidx.annotation.Nullable;
107
import androidx.annotation.StringRes;
8+
import androidx.core.graphics.Insets;
9+
import androidx.core.view.OnApplyWindowInsetsListener;
10+
import androidx.core.view.ViewCompat;
11+
import androidx.core.view.WindowInsetsCompat;
12+
import androidx.lifecycle.LifecycleOwner;
13+
import androidx.lifecycle.MutableLiveData;
14+
import androidx.lifecycle.Observer;
1115
import com.gyf.immersionbar.ImmersionBar;
1216
import com.hjq.bar.TitleBar;
1317
import com.hjq.base.BaseActivity;
14-
import com.hjq.core.tools.AndroidVersion;
1518
import com.hjq.demo.R;
1619
import com.hjq.demo.action.ImmersionAction;
1720
import com.hjq.demo.action.TitleBarAction;
@@ -35,6 +38,12 @@ public abstract class AppActivity extends BaseActivity
3538
private TitleBar mTitleBar;
3639
/** 状态栏沉浸 */
3740
private ImmersionBar mImmersionBar;
41+
/** 状态栏高度 LiveData */
42+
@NonNull
43+
private final MutableLiveData<Integer> mStatusBarHeightLiveData = new MutableLiveData<>();
44+
/** 导航栏高度 LiveData */
45+
@NonNull
46+
private final MutableLiveData<Integer> mNavigationBarHeightLiveData = new MutableLiveData<>();
3847

3948
/** 加载对话框 */
4049
private WaitDialog.Builder mDialog;
@@ -110,38 +119,75 @@ protected void initLayout() {
110119
getStatusBarConfig().init();
111120
}
112121

113-
// 适配 Android 15 EdgeToEdge 特性
114-
if (AndroidVersion.isAndroid15()) {
115-
getWindow().getDecorView().setOnApplyWindowInsetsListener(new OnApplyWindowInsetsListener() {
116-
117-
@NonNull
118-
@Override
119-
public WindowInsets onApplyWindowInsets(@NonNull View v, @NonNull WindowInsets insets) {
120-
Insets systemBars = insets.getInsets(WindowInsets.Type.systemBars());
121-
View immersionTopView = getImmersionTopView();
122-
View immersionBottomView = getImmersionBottomView();
123-
if (immersionTopView != null && immersionTopView == immersionBottomView) {
124-
immersionTopView.setPadding(immersionTopView.getPaddingLeft(), systemBars.top,
125-
immersionTopView.getPaddingRight(), systemBars.bottom);
126-
return insets;
127-
}
128-
if (immersionTopView != null) {
129-
immersionTopView.setPadding(immersionTopView.getPaddingLeft(), systemBars.top,
130-
immersionTopView.getPaddingRight(), immersionTopView.getPaddingBottom());
131-
}
132-
if (immersionBottomView != null) {
133-
immersionBottomView.setPadding(immersionBottomView.getPaddingLeft(), immersionBottomView.getPaddingTop(),
134-
immersionBottomView.getPaddingRight(), systemBars.bottom);
135-
}
136-
return insets;
137-
}
138-
});
139-
} else {
122+
// 监听状态栏和导航栏高度变化
123+
mStatusBarHeightLiveData.observe(this, statusBarHeight -> {
124+
if (statusBarHeight == null) {
125+
return;
126+
}
140127
View immersionTopView = getImmersionTopView();
141-
if (immersionTopView != null) {
142-
ImmersionBar.setTitleBar(this, immersionTopView);
128+
if (immersionTopView == null) {
129+
return;
143130
}
144-
}
131+
immersionTopView.setPadding(immersionTopView.getPaddingLeft(), statusBarHeight,
132+
immersionTopView.getPaddingRight(), immersionTopView.getPaddingBottom());
133+
});
134+
mNavigationBarHeightLiveData.observe(this, navigationBarHeight -> {
135+
if (navigationBarHeight == null) {
136+
return;
137+
}
138+
View immersionBottomView = getImmersionBottomView();
139+
if (immersionBottomView == null) {
140+
return;
141+
}
142+
immersionBottomView.setPadding(immersionBottomView.getPaddingLeft(), immersionBottomView.getPaddingTop(),
143+
immersionBottomView.getPaddingRight(), navigationBarHeight);
144+
});
145+
ViewCompat.setOnApplyWindowInsetsListener(getWindow().getDecorView(), new OnApplyWindowInsetsListener() {
146+
147+
@NonNull
148+
@Override
149+
public WindowInsetsCompat onApplyWindowInsets(@NonNull View v, @NonNull WindowInsetsCompat insets) {
150+
Insets windowInsets = getWindowInsets(insets);
151+
Integer statusBarHeight = mStatusBarHeightLiveData.getValue();
152+
if (statusBarHeight == null || statusBarHeight != windowInsets.top) {
153+
mStatusBarHeightLiveData.postValue(windowInsets.top);
154+
}
155+
Integer navigationBarHeight = mNavigationBarHeightLiveData.getValue();
156+
if (navigationBarHeight == null || navigationBarHeight != windowInsets.bottom) {
157+
mNavigationBarHeightLiveData.postValue(windowInsets.bottom);
158+
}
159+
return insets;
160+
}
161+
});
162+
}
163+
164+
/**
165+
* 获取系统栏的高度
166+
*/
167+
public Insets getWindowInsets(@NonNull WindowInsetsCompat insets) {
168+
return insets.getInsets(WindowInsetsCompat.Type.systemBars());
169+
}
170+
171+
/**
172+
* 监听状态栏高度变化
173+
*/
174+
public void observeStatusBarHeight(@NonNull Observer<Integer> observer) {
175+
observeStatusBarHeight(this, observer);
176+
}
177+
178+
public void observeStatusBarHeight(@NonNull LifecycleOwner lifecycleOwner, @NonNull Observer<Integer> observer) {
179+
mStatusBarHeightLiveData.observe(lifecycleOwner, observer);
180+
}
181+
182+
/**
183+
* 监听导航栏高度变化
184+
*/
185+
public void observeNavigationBarHeight(@NonNull Observer<Integer> observer) {
186+
observeNavigationBarHeight(this, observer);
187+
}
188+
189+
public void observeNavigationBarHeight(@NonNull LifecycleOwner lifecycleOwner, @NonNull Observer<Integer> observer) {
190+
mNavigationBarHeightLiveData.observe(lifecycleOwner, observer);
145191
}
146192

147193
/**
@@ -155,6 +201,15 @@ protected boolean isStatusBarEnabled() {
155201
* 状态栏字体深色模式
156202
*/
157203
protected boolean isStatusBarDarkFont() {
204+
// 返回 true 表示黑色字体
205+
return true;
206+
}
207+
208+
/**
209+
* 获取导航栏图标颜色
210+
*/
211+
protected boolean isNavigationBarDarkIcon() {
212+
// 返回 true 表示黑色图标
158213
return true;
159214
}
160215

@@ -174,20 +229,13 @@ public ImmersionBar getStatusBarConfig() {
174229
*/
175230
@NonNull
176231
protected ImmersionBar createStatusBarConfig() {
177-
ImmersionBar immersionBar = ImmersionBar.with(this)
178-
// 默认状态栏字体颜色为黑色
232+
return ImmersionBar.with(this)
233+
// 设置状态栏字体的颜色
179234
.statusBarDarkFont(isStatusBarDarkFont())
180-
// 状态栏字体和导航栏内容自动变色,必须指定状态栏颜色和导航栏颜色才可以自动变色
181-
.autoDarkModeEnable(true, 0.2f);
182-
// 适配 Android 15 EdgeToEdge 特性
183-
if (AndroidVersion.isAndroid15()) {
184235
// 设置透明的导航栏
185-
immersionBar.transparentNavigationBar();
186-
} else {
187-
// 指定导航栏背景颜色
188-
immersionBar.navigationBarColor(R.color.white);
189-
}
190-
return immersionBar;
236+
.transparentNavigationBar()
237+
// 设置导航栏图标的颜色
238+
.navigationBarDarkIcon(isNavigationBarDarkIcon());
191239
}
192240

193241
/**

‎app/src/main/java/com/hjq/demo/app/TitleBarFragment.java‎

Lines changed: 73 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
package com.hjq.demo.app;
22

3-
import android.graphics.Insets;
43
import android.os.Bundle;
54
import android.view.View;
6-
import android.view.View.OnApplyWindowInsetsListener;
7-
import android.view.WindowInsets;
85
import androidx.annotation.NonNull;
96
import androidx.annotation.Nullable;
7+
import androidx.lifecycle.LifecycleOwner;
8+
import androidx.lifecycle.MutableLiveData;
9+
import androidx.lifecycle.Observer;
1010
import com.gyf.immersionbar.ImmersionBar;
1111
import com.hjq.bar.TitleBar;
12-
import com.hjq.core.tools.AndroidVersion;
13-
import com.hjq.demo.R;
1412
import com.hjq.demo.action.ImmersionAction;
1513
import com.hjq.demo.action.TitleBarAction;
1614

@@ -21,12 +19,18 @@
2119
* desc : 带标题栏的 Fragment 业务基类
2220
*/
2321
public abstract class TitleBarFragment<A extends AppActivity>
24-
extends AppFragment<A> implements TitleBarAction, ImmersionAction {
22+
extends AppFragment<A> implements TitleBarAction, ImmersionAction {
2523

2624
/** 标题栏对象 */
2725
private TitleBar mTitleBar;
2826
/** 状态栏沉浸 */
2927
private ImmersionBar mImmersionBar;
28+
/** 状态栏高度 LiveData */
29+
@NonNull
30+
private final MutableLiveData<Integer> mStatusBarHeightLiveData = new MutableLiveData<>();
31+
/** 导航栏高度 LiveData */
32+
@NonNull
33+
private final MutableLiveData<Integer> mNavigationBarHeightLiveData = new MutableLiveData<>();
3034

3135
@Override
3236
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
@@ -43,40 +47,58 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
4347
getStatusBarConfig().init();
4448
}
4549

46-
// 适配 Android 15 EdgeToEdge 特性
47-
if (AndroidVersion.isAndroid15()) {
48-
view.setOnApplyWindowInsetsListener(new OnApplyWindowInsetsListener() {
49-
50-
@NonNull
51-
@Override
52-
public WindowInsets onApplyWindowInsets(@NonNull View v, @NonNull WindowInsets insets) {
53-
Insets systemBars = insets.getInsets(WindowInsets.Type.systemBars());
54-
View immersionTopView = getImmersionTopView();
55-
View immersionBottomView = getImmersionBottomView();
56-
if (immersionTopView != null && immersionTopView == immersionBottomView) {
57-
immersionTopView.setPadding(immersionTopView.getPaddingLeft(), systemBars.top,
58-
immersionTopView.getPaddingRight(), systemBars.bottom);
59-
return insets;
60-
}
61-
if (immersionTopView != null) {
62-
immersionTopView.setPadding(immersionTopView.getPaddingLeft(), systemBars.top,
63-
immersionTopView.getPaddingRight(), immersionTopView.getPaddingBottom());
64-
}
65-
if (immersionBottomView != null) {
66-
immersionBottomView.setPadding(immersionBottomView.getPaddingLeft(), immersionBottomView.getPaddingTop(),
67-
immersionBottomView.getPaddingRight(), systemBars.bottom);
68-
}
69-
return insets;
50+
A attachActivity = getAttachActivity();
51+
if (attachActivity != null) {
52+
// 监听状态栏和导航栏高度变化
53+
mStatusBarHeightLiveData.observe(this, statusBarHeight -> {
54+
if (statusBarHeight == null) {
55+
return;
7056
}
57+
View immersionTopView = getImmersionTopView();
58+
if (immersionTopView == null) {
59+
return;
60+
}
61+
immersionTopView.setPadding(immersionTopView.getPaddingLeft(), statusBarHeight,
62+
immersionTopView.getPaddingRight(), immersionTopView.getPaddingBottom());
7163
});
72-
} else {
73-
View immersionTopView = getImmersionTopView();
74-
if (immersionTopView != null) {
75-
ImmersionBar.setTitleBar(this, immersionTopView);
76-
}
64+
mNavigationBarHeightLiveData.observe(this, navigationBarHeight -> {
65+
if (navigationBarHeight == null) {
66+
return;
67+
}
68+
View immersionBottomView = getImmersionBottomView();
69+
if (immersionBottomView == null) {
70+
return;
71+
}
72+
immersionBottomView.setPadding(immersionBottomView.getPaddingLeft(), immersionBottomView.getPaddingTop(),
73+
immersionBottomView.getPaddingRight(), navigationBarHeight);
74+
});
75+
attachActivity.observeStatusBarHeight(mStatusBarHeightLiveData::postValue);
76+
attachActivity.observeNavigationBarHeight(mNavigationBarHeightLiveData::postValue);
7777
}
7878
}
7979

80+
/**
81+
* 监听状态栏高度变化
82+
*/
83+
public void observeStatusBarHeight(@NonNull Observer<Integer> observer) {
84+
observeStatusBarHeight(this, observer);
85+
}
86+
87+
public void observeStatusBarHeight(@NonNull LifecycleOwner lifecycleOwner, @NonNull Observer<Integer> observer) {
88+
mStatusBarHeightLiveData.observe(lifecycleOwner, observer);
89+
}
90+
91+
/**
92+
* 监听导航栏高度变化
93+
*/
94+
public void observeNavigationBarHeight(@NonNull Observer<Integer> observer) {
95+
observeNavigationBarHeight(this, observer);
96+
}
97+
98+
public void observeNavigationBarHeight(@NonNull LifecycleOwner lifecycleOwner, @NonNull Observer<Integer> observer) {
99+
mNavigationBarHeightLiveData.observe(lifecycleOwner, observer);
100+
}
101+
80102
@Override
81103
public void onResume() {
82104
super.onResume();
@@ -109,20 +131,13 @@ protected ImmersionBar getStatusBarConfig() {
109131
*/
110132
@NonNull
111133
protected ImmersionBar createStatusBarConfig() {
112-
ImmersionBar immersionBar = ImmersionBar.with(this)
113-
// 默认状态栏字体颜色为黑色
134+
return ImmersionBar.with(this)
135+
// 设置状态栏字体的颜色
114136
.statusBarDarkFont(isStatusBarDarkFont())
115-
// 状态栏字体和导航栏内容自动变色,必须指定状态栏颜色和导航栏颜色才可以自动变色
116-
.autoDarkModeEnable(true, 0.2f);
117-
// 适配 Android 15 EdgeToEdge 特性
118-
if (AndroidVersion.isAndroid15()) {
119137
// 设置透明的导航栏
120-
immersionBar.transparentNavigationBar();
121-
} else {
122-
// 指定导航栏背景颜色
123-
immersionBar.navigationBarColor(R.color.white);
124-
}
125-
return immersionBar;
138+
.transparentNavigationBar()
139+
// 设置导航栏图标的颜色
140+
.navigationBarDarkIcon(isNavigationBarDarkIcon());
126141
}
127142

128143
/**
@@ -133,10 +148,20 @@ protected boolean isStatusBarDarkFont() {
133148
if (activity == null) {
134149
return false;
135150
}
136-
// 返回真表示黑色字体
137151
return activity.isStatusBarDarkFont();
138152
}
139153

154+
/**
155+
* 获取导航栏图标颜色
156+
*/
157+
protected boolean isNavigationBarDarkIcon() {
158+
A activity = getAttachActivity();
159+
if (activity == null) {
160+
return false;
161+
}
162+
return activity.isNavigationBarDarkIcon();
163+
}
164+
140165
@Override
141166
@Nullable
142167
public TitleBar acquireTitleBar() {

‎app/src/main/java/com/hjq/demo/ui/activity/GuideActivity.java‎

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import androidx.annotation.NonNull;
77
import androidx.annotation.Nullable;
88
import androidx.viewpager2.widget.ViewPager2;
9-
import com.gyf.immersionbar.ImmersionBar;
109
import com.hjq.demo.R;
1110
import com.hjq.demo.aop.SingleClick;
1211
import com.hjq.demo.app.AppActivity;
@@ -106,12 +105,4 @@ protected void onDestroy() {
106105
super.onDestroy();
107106
mViewPager.unregisterOnPageChangeCallback(mCallback);
108107
}
109-
110-
@NonNull
111-
@Override
112-
protected ImmersionBar createStatusBarConfig() {
113-
return super.createStatusBarConfig()
114-
// 指定导航栏背景颜色
115-
.navigationBarColor(R.color.white);
116-
}
117108
}

0 commit comments

Comments
 (0)