Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/dull-sheep-float.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@capawesome/capacitor-android-edge-to-edge-support': minor
---

feat(android): add support for status bar and navigation bar color customization
82 changes: 71 additions & 11 deletions packages/android-edge-to-edge-support/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,11 @@ Otherwise, the web view will be resized to fit the screen, which may cause issue
<docgen-config>
<!--Update the source file JSDoc comments and rerun docgen to update the docs below-->

| Prop | Type | Description | Since |
| --------------------- | ------------------- | ------------------------------------------------------------------------------------------ | ----- |
| **`backgroundColor`** | <code>string</code> | The hexadecimal color to set as the background color of the status bar and navigation bar. | 7.1.0 |
| Prop | Type | Description | Since |
| ------------------------ | ------------------- | ----------------------------------------------------------------------------------------------------------- | ----- |
| **`backgroundColor`** | <code>string</code> | The hexadecimal color to set as the background color of the status bar and navigation bar. | 7.1.0 |
| **`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 |
| **`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 |

### Examples

Expand All @@ -60,7 +62,9 @@ In `capacitor.config.json`:
{
"plugins": {
"EdgeToEdge": {
"backgroundColor": "#ffffff"
"backgroundColor": "#ffffff",
"navigationBarColor": "#000000",
"statusBarColor": "#ffffff"
}
}
}
Expand All @@ -77,6 +81,8 @@ const config: CapacitorConfig = {
plugins: {
EdgeToEdge: {
backgroundColor: "#ffffff",
navigationBarColor: "#000000",
statusBarColor: "#ffffff",
},
},
};
Expand Down Expand Up @@ -122,24 +128,26 @@ const setLightStyle = async () => {

<docgen-index>

* [`enable()`](#enable)
* [`disable()`](#disable)
* [`enable()`](#enable)
* [`getInsets()`](#getinsets)
* [`setBackgroundColor(...)`](#setbackgroundcolor)
* [`setNavigationBarColor(...)`](#setnavigationbarcolor)
* [`setStatusBarColor(...)`](#setstatusbarcolor)
* [Interfaces](#interfaces)

</docgen-index>

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

### enable()
### disable()

```typescript
enable() => Promise<void>
disable() => Promise<void>
```

Enable the edge-to-edge mode.
Disable the edge-to-edge mode.

Only available on Android.

Expand All @@ -148,13 +156,13 @@ Only available on Android.
--------------------


### disable()
### enable()

```typescript
disable() => Promise<void>
enable() => Promise<void>
```

Disable the edge-to-edge mode.
Enable the edge-to-edge mode.

Only available on Android.

Expand Down Expand Up @@ -199,6 +207,44 @@ Only available on Android.
--------------------


### setNavigationBarColor(...)

```typescript
setNavigationBarColor(options: SetNavigationBarColorOptions) => Promise<void>
```

Set the background color of the navigation bar area.

Only available on Android.

| Param | Type |
| ------------- | ------------------------------------------------------------------------------------- |
| **`options`** | <code><a href="#setnavigationbarcoloroptions">SetNavigationBarColorOptions</a></code> |

**Since:** 8.0.0

--------------------


### setStatusBarColor(...)

```typescript
setStatusBarColor(options: SetStatusBarColorOptions) => Promise<void>
```

Set the background color of the status bar area.

Only available on Android.

| Param | Type |
| ------------- | ----------------------------------------------------------------------------- |
| **`options`** | <code><a href="#setstatusbarcoloroptions">SetStatusBarColorOptions</a></code> |

**Since:** 8.0.0

--------------------


### Interfaces


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


#### SetNavigationBarColorOptions

| Prop | Type | Description | Since |
| ----------- | ------------------- | -------------------------------------------------------------------------------- | ----- |
| **`color`** | <code>string</code> | The hexadecimal color to set as the background color of the navigation bar area. | 8.0.0 |


#### SetStatusBarColorOptions

| Prop | Type | Description | Since |
| ----------- | ------------------- | ---------------------------------------------------------------------------- | ----- |
| **`color`** | <code>string</code> | The hexadecimal color to set as the background color of the status bar area. | 8.0.0 |

</docgen-api>

## FAQ
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@

import android.graphics.Color;
import android.os.Build;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import com.getcapacitor.Logger;
import java.lang.reflect.Constructor;

public class EdgeToEdge {

Expand All @@ -18,11 +22,21 @@ public class EdgeToEdge {
@NonNull
private final EdgeToEdgePlugin plugin;

@Nullable
private View navigationBarOverlay;

@Nullable
private View statusBarOverlay;

public EdgeToEdge(@NonNull EdgeToEdgePlugin plugin, @NonNull EdgeToEdgeConfig config) {
this.config = config;
this.plugin = plugin;
// Apply insets to disable the edge-to-edge feature
setBackgroundColor(config.getBackgroundColor());
// Create color overlays
createColorOverlays();
// Set colors from config
setStatusBarColor(config.getStatusBarColor());
setNavigationBarColor(config.getNavigationBarColor());
// Apply insets to enable the edge-to-edge feature
applyInsets();
}

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

public void setBackgroundColor(String color) {
setBackgroundColor(Color.parseColor(color));
int parsedColor = Color.parseColor(color);
setStatusBarColor(parsedColor);
setNavigationBarColor(parsedColor);
}

public void setNavigationBarColor(String color) {
setNavigationBarColor(Color.parseColor(color));
}

public void setStatusBarColor(String color) {
setStatusBarColor(Color.parseColor(color));
}

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

view.setLayoutParams(mlp);

// Update color overlays based on current insets
updateColorOverlays(systemBarsInsets);
}
// Set listener
ViewCompat.setOnApplyWindowInsetsListener(view, (v, windowInsets) -> {
Expand All @@ -87,6 +114,9 @@ private void applyInsets() {

v.setLayoutParams(mlp);

// Update color overlays based on current insets
updateColorOverlays(systemBarsInsets);

return WindowInsetsCompat.CONSUMED;
});
}
Expand All @@ -104,13 +134,105 @@ private void removeInsets() {
view.setLayoutParams(mlp);
// Reset listener
ViewCompat.setOnApplyWindowInsetsListener(view, null);
// Remove color overlays
removeColorOverlays();
}

private void setBackgroundColor(int color) {
View view = plugin.getBridge().getWebView();
// Get parent view
ViewGroup parent = (ViewGroup) view.getParent();
// Set background color
parent.setBackgroundColor(color);
private void createColorOverlays() {
View webView = plugin.getBridge().getWebView();
ViewGroup parent = (ViewGroup) webView.getParent();

if (statusBarOverlay == null) {
statusBarOverlay = new View(parent.getContext());
parent.addView(statusBarOverlay, 0); // Add behind webview
}

if (navigationBarOverlay == null) {
navigationBarOverlay = new View(parent.getContext());
parent.addView(navigationBarOverlay, 0); // Add behind webview
}
}

private void removeColorOverlays() {
View webView = plugin.getBridge().getWebView();
ViewGroup parent = (ViewGroup) webView.getParent();

if (statusBarOverlay != null) {
parent.removeView(statusBarOverlay);
statusBarOverlay = null;
}

if (navigationBarOverlay != null) {
parent.removeView(navigationBarOverlay);
navigationBarOverlay = null;
}
}

private void setNavigationBarColor(int color) {
if (navigationBarOverlay != null) {
navigationBarOverlay.setBackgroundColor(color);
}
}

private void setStatusBarColor(int color) {
if (statusBarOverlay != null) {
statusBarOverlay.setBackgroundColor(color);
}
}

private void updateColorOverlays(Insets systemBarsInsets) {
View webView = plugin.getBridge().getWebView();
ViewGroup parent = (ViewGroup) webView.getParent();

if (statusBarOverlay != null) {
// Position status bar overlay at top
ViewGroup.LayoutParams statusParams = createLayoutParams(
parent,
ViewGroup.LayoutParams.MATCH_PARENT,
systemBarsInsets.top,
Gravity.TOP
);
statusBarOverlay.setLayoutParams(statusParams);
}

if (navigationBarOverlay != null) {
// Position navigation bar overlay at bottom
ViewGroup.LayoutParams navParams = createLayoutParams(
parent,
ViewGroup.LayoutParams.MATCH_PARENT,
systemBarsInsets.bottom,
Gravity.BOTTOM
);
navigationBarOverlay.setLayoutParams(navParams);
}
}

private ViewGroup.LayoutParams createLayoutParams(ViewGroup parent, int width, int height, int gravity) {
String parentClassName = parent.getClass().getName();

// Handle CoordinatorLayout using reflection
if (parentClassName.contains("CoordinatorLayout")) {
try {
Class<?> layoutParamsClass = Class.forName("androidx.coordinatorlayout.widget.CoordinatorLayout$LayoutParams");
Constructor<?> constructor = layoutParamsClass.getConstructor(int.class, int.class);
ViewGroup.LayoutParams params = (ViewGroup.LayoutParams) constructor.newInstance(width, height);
// Set gravity using reflection
layoutParamsClass.getField("gravity").setInt(params, gravity);
return params;
} catch (Exception e) {
Logger.error("EdgeToEdge", "Failed to create CoordinatorLayout.LayoutParams", e);
}
}

// Handle FrameLayout
if (parent instanceof FrameLayout) {
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(width, height);
params.gravity = gravity;
return params;
}

// Fallback to MarginLayoutParams
ViewGroup.MarginLayoutParams params = new ViewGroup.MarginLayoutParams(width, height);
return params;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,30 @@
public class EdgeToEdgeConfig {

private int backgroundColor = Color.TRANSPARENT;
private int navigationBarColor = Color.TRANSPARENT;
private int statusBarColor = Color.TRANSPARENT;

public int getBackgroundColor() {
return this.backgroundColor;
}

public int getNavigationBarColor() {
return this.navigationBarColor;
}

public int getStatusBarColor() {
return this.statusBarColor;
}

public void setBackgroundColor(int backgroundColor) {
this.backgroundColor = backgroundColor;
}

public void setNavigationBarColor(int navigationBarColor) {
this.navigationBarColor = navigationBarColor;
}

public void setStatusBarColor(int statusBarColor) {
this.statusBarColor = statusBarColor;
}
}
Loading