Skip to content

Commit ec619da

Browse files
authored
feat(android-edge-to-edge-support): add support for status bar and navigation bar color customization (#712)
1 parent 5a342c9 commit ec619da

10 files changed

Lines changed: 434 additions & 29 deletions

File tree

.changeset/dull-sheep-float.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@capawesome/capacitor-android-edge-to-edge-support': minor
3+
---
4+
5+
feat(android): add support for status bar and navigation bar color customization

packages/android-edge-to-edge-support/README.md

Lines changed: 71 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,11 @@ Otherwise, the web view will be resized to fit the screen, which may cause issue
4848
<docgen-config>
4949
<!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
5050

51-
| Prop | Type | Description | Since |
52-
| --------------------- | ------------------- | ------------------------------------------------------------------------------------------ | ----- |
53-
| **`backgroundColor`** | <code>string</code> | The hexadecimal color to set as the background color of the status bar and navigation bar. | 7.1.0 |
51+
| Prop | Type | Description | Since |
52+
| ------------------------ | ------------------- | ----------------------------------------------------------------------------------------------------------- | ----- |
53+
| **`backgroundColor`** | <code>string</code> | The hexadecimal color to set as the background color of the status bar and navigation bar. | 7.1.0 |
54+
| **`navigationBarColor`** | <code>string</code> | The hexadecimal color to set as the background color of the navigation bar area. Only available on Android. | 8.0.0 |
55+
| **`statusBarColor`** | <code>string</code> | The hexadecimal color to set as the background color of the status bar area. Only available on Android. | 8.0.0 |
5456

5557
### Examples
5658

@@ -60,7 +62,9 @@ In `capacitor.config.json`:
6062
{
6163
"plugins": {
6264
"EdgeToEdge": {
63-
"backgroundColor": "#ffffff"
65+
"backgroundColor": "#ffffff",
66+
"navigationBarColor": "#000000",
67+
"statusBarColor": "#ffffff"
6468
}
6569
}
6670
}
@@ -77,6 +81,8 @@ const config: CapacitorConfig = {
7781
plugins: {
7882
EdgeToEdge: {
7983
backgroundColor: "#ffffff",
84+
navigationBarColor: "#000000",
85+
statusBarColor: "#ffffff",
8086
},
8187
},
8288
};
@@ -122,24 +128,26 @@ const setLightStyle = async () => {
122128

123129
<docgen-index>
124130

125-
* [`enable()`](#enable)
126131
* [`disable()`](#disable)
132+
* [`enable()`](#enable)
127133
* [`getInsets()`](#getinsets)
128134
* [`setBackgroundColor(...)`](#setbackgroundcolor)
135+
* [`setNavigationBarColor(...)`](#setnavigationbarcolor)
136+
* [`setStatusBarColor(...)`](#setstatusbarcolor)
129137
* [Interfaces](#interfaces)
130138

131139
</docgen-index>
132140

133141
<docgen-api>
134142
<!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
135143

136-
### enable()
144+
### disable()
137145

138146
```typescript
139-
enable() => Promise<void>
147+
disable() => Promise<void>
140148
```
141149

142-
Enable the edge-to-edge mode.
150+
Disable the edge-to-edge mode.
143151

144152
Only available on Android.
145153

@@ -148,13 +156,13 @@ Only available on Android.
148156
--------------------
149157

150158

151-
### disable()
159+
### enable()
152160

153161
```typescript
154-
disable() => Promise<void>
162+
enable() => Promise<void>
155163
```
156164

157-
Disable the edge-to-edge mode.
165+
Enable the edge-to-edge mode.
158166

159167
Only available on Android.
160168

@@ -199,6 +207,44 @@ Only available on Android.
199207
--------------------
200208

201209

210+
### setNavigationBarColor(...)
211+
212+
```typescript
213+
setNavigationBarColor(options: SetNavigationBarColorOptions) => Promise<void>
214+
```
215+
216+
Set the background color of the navigation bar area.
217+
218+
Only available on Android.
219+
220+
| Param | Type |
221+
| ------------- | ------------------------------------------------------------------------------------- |
222+
| **`options`** | <code><a href="#setnavigationbarcoloroptions">SetNavigationBarColorOptions</a></code> |
223+
224+
**Since:** 8.0.0
225+
226+
--------------------
227+
228+
229+
### setStatusBarColor(...)
230+
231+
```typescript
232+
setStatusBarColor(options: SetStatusBarColorOptions) => Promise<void>
233+
```
234+
235+
Set the background color of the status bar area.
236+
237+
Only available on Android.
238+
239+
| Param | Type |
240+
| ------------- | ----------------------------------------------------------------------------- |
241+
| **`options`** | <code><a href="#setstatusbarcoloroptions">SetStatusBarColorOptions</a></code> |
242+
243+
**Since:** 8.0.0
244+
245+
--------------------
246+
247+
202248
### Interfaces
203249

204250

@@ -218,6 +264,20 @@ Only available on Android.
218264
| ----------- | ------------------- | ------------------------------------------------------------------------------------------ | ----- |
219265
| **`color`** | <code>string</code> | The hexadecimal color to set as the background color of the status bar and navigation bar. | 7.0.0 |
220266

267+
268+
#### SetNavigationBarColorOptions
269+
270+
| Prop | Type | Description | Since |
271+
| ----------- | ------------------- | -------------------------------------------------------------------------------- | ----- |
272+
| **`color`** | <code>string</code> | The hexadecimal color to set as the background color of the navigation bar area. | 8.0.0 |
273+
274+
275+
#### SetStatusBarColorOptions
276+
277+
| Prop | Type | Description | Since |
278+
| ----------- | ------------------- | ---------------------------------------------------------------------------- | ----- |
279+
| **`color`** | <code>string</code> | The hexadecimal color to set as the background color of the status bar area. | 8.0.0 |
280+
221281
</docgen-api>
222282

223283
## FAQ

packages/android-edge-to-edge-support/android/src/main/java/io/capawesome/capacitorjs/plugins/androidedgetoedgesupport/EdgeToEdge.java

Lines changed: 131 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@
22

33
import android.graphics.Color;
44
import android.os.Build;
5+
import android.view.Gravity;
56
import android.view.View;
67
import android.view.ViewGroup;
8+
import android.widget.FrameLayout;
79
import androidx.annotation.NonNull;
10+
import androidx.annotation.Nullable;
811
import androidx.core.graphics.Insets;
912
import androidx.core.view.ViewCompat;
1013
import androidx.core.view.WindowInsetsCompat;
1114
import com.getcapacitor.Logger;
15+
import java.lang.reflect.Constructor;
1216

1317
public class EdgeToEdge {
1418

@@ -18,11 +22,21 @@ public class EdgeToEdge {
1822
@NonNull
1923
private final EdgeToEdgePlugin plugin;
2024

25+
@Nullable
26+
private View navigationBarOverlay;
27+
28+
@Nullable
29+
private View statusBarOverlay;
30+
2131
public EdgeToEdge(@NonNull EdgeToEdgePlugin plugin, @NonNull EdgeToEdgeConfig config) {
2232
this.config = config;
2333
this.plugin = plugin;
24-
// Apply insets to disable the edge-to-edge feature
25-
setBackgroundColor(config.getBackgroundColor());
34+
// Create color overlays
35+
createColorOverlays();
36+
// Set colors from config
37+
setStatusBarColor(config.getStatusBarColor());
38+
setNavigationBarColor(config.getNavigationBarColor());
39+
// Apply insets to enable the edge-to-edge feature
2640
applyInsets();
2741
}
2842

@@ -40,7 +54,17 @@ public ViewGroup.MarginLayoutParams getInsets() {
4054
}
4155

4256
public void setBackgroundColor(String color) {
43-
setBackgroundColor(Color.parseColor(color));
57+
int parsedColor = Color.parseColor(color);
58+
setStatusBarColor(parsedColor);
59+
setNavigationBarColor(parsedColor);
60+
}
61+
62+
public void setNavigationBarColor(String color) {
63+
setNavigationBarColor(Color.parseColor(color));
64+
}
65+
66+
public void setStatusBarColor(String color) {
67+
setStatusBarColor(Color.parseColor(color));
4468
}
4569

4670
private void applyInsets() {
@@ -64,6 +88,9 @@ private void applyInsets() {
6488
mlp.rightMargin = systemBarsInsets.right;
6589

6690
view.setLayoutParams(mlp);
91+
92+
// Update color overlays based on current insets
93+
updateColorOverlays(systemBarsInsets);
6794
}
6895
// Set listener
6996
ViewCompat.setOnApplyWindowInsetsListener(view, (v, windowInsets) -> {
@@ -87,6 +114,9 @@ private void applyInsets() {
87114

88115
v.setLayoutParams(mlp);
89116

117+
// Update color overlays based on current insets
118+
updateColorOverlays(systemBarsInsets);
119+
90120
return WindowInsetsCompat.CONSUMED;
91121
});
92122
}
@@ -104,13 +134,105 @@ private void removeInsets() {
104134
view.setLayoutParams(mlp);
105135
// Reset listener
106136
ViewCompat.setOnApplyWindowInsetsListener(view, null);
137+
// Remove color overlays
138+
removeColorOverlays();
107139
}
108140

109-
private void setBackgroundColor(int color) {
110-
View view = plugin.getBridge().getWebView();
111-
// Get parent view
112-
ViewGroup parent = (ViewGroup) view.getParent();
113-
// Set background color
114-
parent.setBackgroundColor(color);
141+
private void createColorOverlays() {
142+
View webView = plugin.getBridge().getWebView();
143+
ViewGroup parent = (ViewGroup) webView.getParent();
144+
145+
if (statusBarOverlay == null) {
146+
statusBarOverlay = new View(parent.getContext());
147+
parent.addView(statusBarOverlay, 0); // Add behind webview
148+
}
149+
150+
if (navigationBarOverlay == null) {
151+
navigationBarOverlay = new View(parent.getContext());
152+
parent.addView(navigationBarOverlay, 0); // Add behind webview
153+
}
154+
}
155+
156+
private void removeColorOverlays() {
157+
View webView = plugin.getBridge().getWebView();
158+
ViewGroup parent = (ViewGroup) webView.getParent();
159+
160+
if (statusBarOverlay != null) {
161+
parent.removeView(statusBarOverlay);
162+
statusBarOverlay = null;
163+
}
164+
165+
if (navigationBarOverlay != null) {
166+
parent.removeView(navigationBarOverlay);
167+
navigationBarOverlay = null;
168+
}
169+
}
170+
171+
private void setNavigationBarColor(int color) {
172+
if (navigationBarOverlay != null) {
173+
navigationBarOverlay.setBackgroundColor(color);
174+
}
175+
}
176+
177+
private void setStatusBarColor(int color) {
178+
if (statusBarOverlay != null) {
179+
statusBarOverlay.setBackgroundColor(color);
180+
}
181+
}
182+
183+
private void updateColorOverlays(Insets systemBarsInsets) {
184+
View webView = plugin.getBridge().getWebView();
185+
ViewGroup parent = (ViewGroup) webView.getParent();
186+
187+
if (statusBarOverlay != null) {
188+
// Position status bar overlay at top
189+
ViewGroup.LayoutParams statusParams = createLayoutParams(
190+
parent,
191+
ViewGroup.LayoutParams.MATCH_PARENT,
192+
systemBarsInsets.top,
193+
Gravity.TOP
194+
);
195+
statusBarOverlay.setLayoutParams(statusParams);
196+
}
197+
198+
if (navigationBarOverlay != null) {
199+
// Position navigation bar overlay at bottom
200+
ViewGroup.LayoutParams navParams = createLayoutParams(
201+
parent,
202+
ViewGroup.LayoutParams.MATCH_PARENT,
203+
systemBarsInsets.bottom,
204+
Gravity.BOTTOM
205+
);
206+
navigationBarOverlay.setLayoutParams(navParams);
207+
}
208+
}
209+
210+
private ViewGroup.LayoutParams createLayoutParams(ViewGroup parent, int width, int height, int gravity) {
211+
String parentClassName = parent.getClass().getName();
212+
213+
// Handle CoordinatorLayout using reflection
214+
if (parentClassName.contains("CoordinatorLayout")) {
215+
try {
216+
Class<?> layoutParamsClass = Class.forName("androidx.coordinatorlayout.widget.CoordinatorLayout$LayoutParams");
217+
Constructor<?> constructor = layoutParamsClass.getConstructor(int.class, int.class);
218+
ViewGroup.LayoutParams params = (ViewGroup.LayoutParams) constructor.newInstance(width, height);
219+
// Set gravity using reflection
220+
layoutParamsClass.getField("gravity").setInt(params, gravity);
221+
return params;
222+
} catch (Exception e) {
223+
Logger.error("EdgeToEdge", "Failed to create CoordinatorLayout.LayoutParams", e);
224+
}
225+
}
226+
227+
// Handle FrameLayout
228+
if (parent instanceof FrameLayout) {
229+
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(width, height);
230+
params.gravity = gravity;
231+
return params;
232+
}
233+
234+
// Fallback to MarginLayoutParams
235+
ViewGroup.MarginLayoutParams params = new ViewGroup.MarginLayoutParams(width, height);
236+
return params;
115237
}
116238
}

packages/android-edge-to-edge-support/android/src/main/java/io/capawesome/capacitorjs/plugins/androidedgetoedgesupport/EdgeToEdgeConfig.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,30 @@
55
public class EdgeToEdgeConfig {
66

77
private int backgroundColor = Color.TRANSPARENT;
8+
private int navigationBarColor = Color.TRANSPARENT;
9+
private int statusBarColor = Color.TRANSPARENT;
810

911
public int getBackgroundColor() {
1012
return this.backgroundColor;
1113
}
1214

15+
public int getNavigationBarColor() {
16+
return this.navigationBarColor;
17+
}
18+
19+
public int getStatusBarColor() {
20+
return this.statusBarColor;
21+
}
22+
1323
public void setBackgroundColor(int backgroundColor) {
1424
this.backgroundColor = backgroundColor;
1525
}
26+
27+
public void setNavigationBarColor(int navigationBarColor) {
28+
this.navigationBarColor = navigationBarColor;
29+
}
30+
31+
public void setStatusBarColor(int statusBarColor) {
32+
this.statusBarColor = statusBarColor;
33+
}
1634
}

0 commit comments

Comments
 (0)