@capgo/capacitor-native-navigation 8.0.24 → 8.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -13
- package/android/src/main/java/app/capgo/nativenavigation/NativeNavigationPlugin.java +468 -36
- package/dist/docs.json +74 -0
- package/dist/esm/components.js +6 -1
- package/dist/esm/components.js.map +1 -1
- package/dist/esm/definitions.d.ts +38 -0
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.js +3 -3
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +9 -4
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +9 -4
- package/dist/plugin.js.map +1 -1
- package/docs/native-liquid-glass-android.webp +0 -0
- package/docs/native-liquid-glass-ios.webp +0 -0
- package/package.json +1 -1
|
@@ -18,16 +18,20 @@ import android.graphics.drawable.Drawable;
|
|
|
18
18
|
import android.graphics.drawable.GradientDrawable;
|
|
19
19
|
import android.graphics.drawable.StateListDrawable;
|
|
20
20
|
import android.os.Build;
|
|
21
|
+
import android.view.ContextThemeWrapper;
|
|
21
22
|
import android.view.Gravity;
|
|
22
23
|
import android.view.Menu;
|
|
23
24
|
import android.view.MenuItem;
|
|
24
25
|
import android.view.View;
|
|
25
26
|
import android.view.ViewGroup;
|
|
26
27
|
import android.view.ViewOutlineProvider;
|
|
28
|
+
import android.view.ViewTreeObserver;
|
|
27
29
|
import android.view.Window;
|
|
28
30
|
import android.view.WindowInsets;
|
|
29
31
|
import android.widget.FrameLayout;
|
|
30
32
|
import android.widget.ImageView;
|
|
33
|
+
import android.widget.TextView;
|
|
34
|
+
import androidx.annotation.RequiresApi;
|
|
31
35
|
import androidx.appcompat.content.res.AppCompatResources;
|
|
32
36
|
import androidx.appcompat.widget.Toolbar;
|
|
33
37
|
import androidx.core.graphics.PathParser;
|
|
@@ -60,16 +64,32 @@ public class NativeNavigationPlugin extends Plugin {
|
|
|
60
64
|
private static final int DEFAULT_NAVBAR_DP = 56;
|
|
61
65
|
// Android uses Material bottom navigation metrics; web/iOS keep their own platform-native tab bar heights.
|
|
62
66
|
private static final int DEFAULT_TABBAR_DP = 80;
|
|
67
|
+
private static final int LIQUID_GLASS_TABBAR_DP = 64;
|
|
68
|
+
private static final int LIQUID_GLASS_TABBAR_MAX_WIDTH_DP = 300;
|
|
69
|
+
private static final int LIQUID_GLASS_TABBAR_SIDE_MARGIN_DP = 30;
|
|
70
|
+
private static final int LIQUID_GLASS_TABBAR_CONTENT_TOP_PADDING_DP = 8;
|
|
71
|
+
private static final int LIQUID_GLASS_TABBAR_CONTENT_TRANSLATION_Y_DP = 6;
|
|
72
|
+
private static final int LIQUID_GLASS_TABBAR_LABEL_TRANSLATION_Y_DP = 3;
|
|
73
|
+
private static final int LIQUID_GLASS_TABBAR_BADGE_VERTICAL_OFFSET_DP = 2;
|
|
63
74
|
private static final int TABBAR_ICON_DP = 24;
|
|
64
75
|
private static final int TABBAR_ITEM_VERTICAL_PADDING_DP = 8;
|
|
76
|
+
private static final int LIQUID_GLASS_TABBAR_ITEM_VERTICAL_PADDING_DP = 4;
|
|
65
77
|
private static final int TABBAR_INDICATOR_DP = 32;
|
|
78
|
+
private static final int LIQUID_GLASS_TABBAR_INDICATOR_DP = 28;
|
|
66
79
|
private static final int TABBAR_INDICATOR_LABEL_PADDING_DP = 4;
|
|
80
|
+
private static final int LIQUID_GLASS_TABBAR_INDICATOR_LABEL_PADDING_DP = 6;
|
|
81
|
+
private static final int TABBAR_FLOATING_BOTTOM_GAP_DP = 10;
|
|
82
|
+
private static final int LIQUID_GLASS_TABBAR_FLOATING_BOTTOM_GAP_DP = 24;
|
|
67
83
|
private static final int DEFAULT_TRANSITION_MS = 350;
|
|
68
84
|
private static final int MENU_ITEM_BASE = 10_000;
|
|
69
85
|
|
|
70
86
|
private final NativeNavigation implementation = new NativeNavigation();
|
|
71
87
|
private FrameLayout navbarContainer;
|
|
72
88
|
private FrameLayout tabbarContainer;
|
|
89
|
+
private GlassBackdropView navbarGlassBackdrop;
|
|
90
|
+
private View navbarGlassSurface;
|
|
91
|
+
private GlassBackdropView tabbarGlassBackdrop;
|
|
92
|
+
private View tabbarGlassSurface;
|
|
73
93
|
private Toolbar toolbar;
|
|
74
94
|
private BottomNavigationView tabbar;
|
|
75
95
|
private ImageView transitionSnapshot;
|
|
@@ -81,6 +101,13 @@ public class NativeNavigationPlugin extends Plugin {
|
|
|
81
101
|
private int activeTransitionMs = DEFAULT_TRANSITION_MS;
|
|
82
102
|
private int tintColor = Color.rgb(0, 122, 255);
|
|
83
103
|
private int inactiveTintColor = Color.rgb(120, 126, 137);
|
|
104
|
+
private GlassOptions defaultGlassOptions = GlassOptions.defaults();
|
|
105
|
+
private GlassOptions navbarGlassOptions = GlassOptions.defaults();
|
|
106
|
+
private GlassOptions tabbarGlassOptions = GlassOptions.defaults();
|
|
107
|
+
private JSObject navbarGlassConfig;
|
|
108
|
+
private JSObject tabbarGlassConfig;
|
|
109
|
+
private int navbarBackgroundColor = Color.argb(225, 255, 255, 255);
|
|
110
|
+
private int tabbarBackgroundColor = Color.argb(235, 255, 255, 255);
|
|
84
111
|
private String activeTransitionId;
|
|
85
112
|
private String activeTransitionDirection = "forward";
|
|
86
113
|
private RectF activeZoomSourceFrame;
|
|
@@ -104,6 +131,9 @@ public class NativeNavigationPlugin extends Plugin {
|
|
|
104
131
|
runOnUiThread(() -> {
|
|
105
132
|
enabled = call.getBoolean("enabled", true);
|
|
106
133
|
contentInsetMode = call.getString("contentInsetMode", contentInsetMode);
|
|
134
|
+
defaultGlassOptions = GlassOptions.from(call.getObject("glass", null), defaultGlassOptions);
|
|
135
|
+
navbarGlassOptions = GlassOptions.from(navbarGlassConfig, defaultGlassOptions);
|
|
136
|
+
tabbarGlassOptions = GlassOptions.from(tabbarGlassConfig, defaultGlassOptions);
|
|
107
137
|
Double duration = call.getDouble("animationDuration");
|
|
108
138
|
if (duration != null) {
|
|
109
139
|
defaultTransitionMs = Math.max(0, duration.intValue());
|
|
@@ -119,6 +149,12 @@ public class NativeNavigationPlugin extends Plugin {
|
|
|
119
149
|
tabbarContainer.setVisibility(View.GONE);
|
|
120
150
|
}
|
|
121
151
|
}
|
|
152
|
+
if (enabled) {
|
|
153
|
+
reapplyVisibleChromeBackgrounds();
|
|
154
|
+
if (tabbar != null) {
|
|
155
|
+
applyTabbarMetrics(tabbar);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
122
158
|
updateInsetsAndNotify();
|
|
123
159
|
call.resolve(insetsResult());
|
|
124
160
|
});
|
|
@@ -166,6 +202,8 @@ public class NativeNavigationPlugin extends Plugin {
|
|
|
166
202
|
|
|
167
203
|
addToolbarItems(nativeToolbar, call.getArray("rightItems", new JSArray()), "right");
|
|
168
204
|
JSObject colors = call.getObject("colors", new JSObject());
|
|
205
|
+
navbarGlassConfig = call.getObject("glass", null);
|
|
206
|
+
navbarGlassOptions = GlassOptions.from(navbarGlassConfig, defaultGlassOptions);
|
|
169
207
|
applyToolbarColors(nativeToolbar, colors);
|
|
170
208
|
navbarContainer.setVisibility(View.VISIBLE);
|
|
171
209
|
layoutChrome();
|
|
@@ -214,6 +252,8 @@ public class NativeNavigationPlugin extends Plugin {
|
|
|
214
252
|
JSONArray tabs = call.getArray("tabs", new JSArray());
|
|
215
253
|
String selectedId = call.getString("selectedId", null);
|
|
216
254
|
JSObject colors = call.getObject("colors", new JSObject());
|
|
255
|
+
tabbarGlassConfig = call.getObject("glass", null);
|
|
256
|
+
tabbarGlassOptions = GlassOptions.from(tabbarGlassConfig, defaultGlassOptions);
|
|
217
257
|
Integer badgeBackground = colorOption(call, colors, "badgeBackgroundColor", "badgeBackground", null);
|
|
218
258
|
Integer badgeText = colorOption(call, colors, "badgeTextColor", "badgeText", null);
|
|
219
259
|
for (int index = 0; index < tabs.length(); index++) {
|
|
@@ -233,6 +273,9 @@ public class NativeNavigationPlugin extends Plugin {
|
|
|
233
273
|
if (tab.has("badge")) {
|
|
234
274
|
nativeTabbar.removeBadge(itemId);
|
|
235
275
|
BadgeDrawable badge = nativeTabbar.getOrCreateBadge(itemId);
|
|
276
|
+
if (isLiquidGlassTabbar()) {
|
|
277
|
+
badge.setVerticalOffset(dp(LIQUID_GLASS_TABBAR_BADGE_VERTICAL_OFFSET_DP));
|
|
278
|
+
}
|
|
236
279
|
if (badgeBackground != null) {
|
|
237
280
|
badge.setBackgroundColor(badgeBackground);
|
|
238
281
|
}
|
|
@@ -595,6 +638,10 @@ public class NativeNavigationPlugin extends Plugin {
|
|
|
595
638
|
FrameLayout root = contentRoot();
|
|
596
639
|
navbarContainer = new FrameLayout(getContext());
|
|
597
640
|
navbarContainer.setElevation(dp(8));
|
|
641
|
+
navbarGlassBackdrop = new GlassBackdropView(getContext());
|
|
642
|
+
navbarGlassSurface = new View(getContext());
|
|
643
|
+
navbarGlassBackdrop.setVisibility(View.GONE);
|
|
644
|
+
navbarGlassSurface.setVisibility(View.GONE);
|
|
598
645
|
toolbar = new Toolbar(getContext());
|
|
599
646
|
toolbar.setPopupTheme(androidx.appcompat.R.style.ThemeOverlay_AppCompat_Light);
|
|
600
647
|
toolbar.setOnMenuItemClickListener((item) -> {
|
|
@@ -607,6 +654,8 @@ public class NativeNavigationPlugin extends Plugin {
|
|
|
607
654
|
return true;
|
|
608
655
|
});
|
|
609
656
|
|
|
657
|
+
navbarContainer.addView(navbarGlassBackdrop);
|
|
658
|
+
navbarContainer.addView(navbarGlassSurface);
|
|
610
659
|
navbarContainer.addView(toolbar);
|
|
611
660
|
if (root != null) {
|
|
612
661
|
root.addView(navbarContainer);
|
|
@@ -626,26 +675,34 @@ public class NativeNavigationPlugin extends Plugin {
|
|
|
626
675
|
FrameLayout root = contentRoot();
|
|
627
676
|
tabbarContainer = new FrameLayout(getContext());
|
|
628
677
|
tabbarContainer.setElevation(dp(12));
|
|
678
|
+
tabbarContainer.setClipChildren(false);
|
|
679
|
+
tabbarContainer.setClipToPadding(false);
|
|
680
|
+
tabbarGlassBackdrop = new GlassBackdropView(getContext());
|
|
681
|
+
tabbarGlassSurface = new View(getContext());
|
|
682
|
+
tabbarGlassBackdrop.setVisibility(View.GONE);
|
|
683
|
+
tabbarGlassSurface.setVisibility(View.GONE);
|
|
629
684
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
public void getOutline(View view, Outline outline) {
|
|
635
|
-
outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), view.getHeight() / 2f);
|
|
636
|
-
}
|
|
685
|
+
ViewOutlineProvider tabbarPillOutlineProvider = new ViewOutlineProvider() {
|
|
686
|
+
@Override
|
|
687
|
+
public void getOutline(View view, Outline outline) {
|
|
688
|
+
outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), view.getHeight() / 2f);
|
|
637
689
|
}
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
690
|
+
};
|
|
691
|
+
tabbarContainer.setClipToOutline(false);
|
|
692
|
+
tabbarContainer.setOutlineProvider(tabbarPillOutlineProvider);
|
|
693
|
+
tabbarGlassBackdrop.setClipToOutline(true);
|
|
694
|
+
tabbarGlassBackdrop.setOutlineProvider(tabbarPillOutlineProvider);
|
|
695
|
+
tabbarGlassSurface.setClipToOutline(true);
|
|
696
|
+
tabbarGlassSurface.setOutlineProvider(tabbarPillOutlineProvider);
|
|
697
|
+
}
|
|
698
|
+
tabbar = new BottomNavigationView(
|
|
699
|
+
new ContextThemeWrapper(getContext(), com.google.android.material.R.style.Theme_MaterialComponents_DayNight)
|
|
700
|
+
);
|
|
642
701
|
tabbar.setElevation(0);
|
|
643
|
-
tabbar.
|
|
702
|
+
tabbar.setClipChildren(false);
|
|
703
|
+
tabbar.setClipToPadding(false);
|
|
644
704
|
tabbar.setItemIconSize(dp(TABBAR_ICON_DP));
|
|
645
|
-
tabbar
|
|
646
|
-
tabbar.setItemPaddingBottom(dp(TABBAR_ITEM_VERTICAL_PADDING_DP));
|
|
647
|
-
tabbar.setItemActiveIndicatorHeight(dp(TABBAR_INDICATOR_DP));
|
|
648
|
-
tabbar.setActiveIndicatorLabelPadding(dp(TABBAR_INDICATOR_LABEL_PADDING_DP));
|
|
705
|
+
applyTabbarMetrics(tabbar);
|
|
649
706
|
tabbar.setBackgroundColor(Color.TRANSPARENT);
|
|
650
707
|
tabbar.setOnItemSelectedListener((item) -> {
|
|
651
708
|
int itemId = item.getItemId();
|
|
@@ -659,14 +716,13 @@ public class NativeNavigationPlugin extends Plugin {
|
|
|
659
716
|
notifyListeners("tabSelect", event);
|
|
660
717
|
return true;
|
|
661
718
|
});
|
|
719
|
+
tabbarContainer.addView(tabbarGlassBackdrop);
|
|
720
|
+
tabbarContainer.addView(tabbarGlassSurface);
|
|
662
721
|
tabbarContainer.addView(tabbar);
|
|
663
722
|
if (root != null) {
|
|
664
723
|
root.addView(tabbarContainer);
|
|
665
724
|
} else {
|
|
666
|
-
getActivity().addContentView(
|
|
667
|
-
tabbarContainer,
|
|
668
|
-
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dp(DEFAULT_TABBAR_DP))
|
|
669
|
-
);
|
|
725
|
+
getActivity().addContentView(tabbarContainer, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, tabbarHeight()));
|
|
670
726
|
}
|
|
671
727
|
return tabbar;
|
|
672
728
|
}
|
|
@@ -1026,6 +1082,7 @@ public class NativeNavigationPlugin extends Plugin {
|
|
|
1026
1082
|
: Color.rgb(20, 24, 32);
|
|
1027
1083
|
int tint = parseColor(colors.getString("tint", null), tintFallback);
|
|
1028
1084
|
int background = parseColor(colors.getString("background", null), backgroundFallback);
|
|
1085
|
+
navbarBackgroundColor = background;
|
|
1029
1086
|
int foreground = parseColor(colors.getString("foreground", null), foregroundFallback);
|
|
1030
1087
|
tintColor = tint;
|
|
1031
1088
|
nativeToolbar.setTitleTextColor(foreground);
|
|
@@ -1036,9 +1093,8 @@ public class NativeNavigationPlugin extends Plugin {
|
|
|
1036
1093
|
tintedIcon.setTint(tint);
|
|
1037
1094
|
nativeToolbar.setNavigationIcon(tintedIcon);
|
|
1038
1095
|
}
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
}
|
|
1096
|
+
nativeToolbar.setBackgroundColor(Color.TRANSPARENT);
|
|
1097
|
+
applyChromeBackground(navbarContainer, navbarGlassBackdrop, navbarGlassSurface, background, navbarGlassOptions, 0f);
|
|
1042
1098
|
for (int index = 0; index < nativeToolbar.getMenu().size(); index++) {
|
|
1043
1099
|
Drawable icon = nativeToolbar.getMenu().getItem(index).getIcon();
|
|
1044
1100
|
if (icon != null) {
|
|
@@ -1057,6 +1113,7 @@ public class NativeNavigationPlugin extends Plugin {
|
|
|
1057
1113
|
int tint = parseColor(colors.getString("tint", null), tintFallback);
|
|
1058
1114
|
int inactiveTint = parseColor(colors.getString("inactiveTint", null), inactiveFallback);
|
|
1059
1115
|
int background = parseColor(colors.getString("background", null), backgroundFallback);
|
|
1116
|
+
tabbarBackgroundColor = background;
|
|
1060
1117
|
tintColor = tint;
|
|
1061
1118
|
inactiveTintColor = inactiveTint;
|
|
1062
1119
|
int[][] states = new int[][] { new int[] { android.R.attr.state_checked }, new int[] {} };
|
|
@@ -1070,14 +1127,91 @@ public class NativeNavigationPlugin extends Plugin {
|
|
|
1070
1127
|
Integer ripple = colorOption(call, colors, "rippleColor", "ripple", null);
|
|
1071
1128
|
nativeTabbar.setItemRippleColor(ripple == null ? null : ColorStateList.valueOf(ripple));
|
|
1072
1129
|
nativeTabbar.setBackgroundColor(Color.TRANSPARENT);
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1130
|
+
applyTabbarMetrics(nativeTabbar);
|
|
1131
|
+
applyChromeBackground(
|
|
1132
|
+
tabbarContainer,
|
|
1133
|
+
tabbarGlassBackdrop,
|
|
1134
|
+
tabbarGlassSurface,
|
|
1135
|
+
background,
|
|
1136
|
+
tabbarGlassOptions,
|
|
1137
|
+
tabbarCornerRadius()
|
|
1138
|
+
);
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
private void reapplyVisibleChromeBackgrounds() {
|
|
1142
|
+
if (navbarContainer != null && navbarContainer.getVisibility() == View.VISIBLE) {
|
|
1143
|
+
applyChromeBackground(navbarContainer, navbarGlassBackdrop, navbarGlassSurface, navbarBackgroundColor, navbarGlassOptions, 0f);
|
|
1144
|
+
}
|
|
1145
|
+
if (tabbarContainer != null && tabbarContainer.getVisibility() == View.VISIBLE) {
|
|
1146
|
+
applyChromeBackground(
|
|
1147
|
+
tabbarContainer,
|
|
1148
|
+
tabbarGlassBackdrop,
|
|
1149
|
+
tabbarGlassSurface,
|
|
1150
|
+
tabbarBackgroundColor,
|
|
1151
|
+
tabbarGlassOptions,
|
|
1152
|
+
tabbarCornerRadius()
|
|
1153
|
+
);
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
private void applyChromeBackground(
|
|
1158
|
+
ViewGroup container,
|
|
1159
|
+
GlassBackdropView backdrop,
|
|
1160
|
+
View surface,
|
|
1161
|
+
int background,
|
|
1162
|
+
GlassOptions glassOptions,
|
|
1163
|
+
float cornerRadius
|
|
1164
|
+
) {
|
|
1165
|
+
if (container == null) {
|
|
1166
|
+
return;
|
|
1167
|
+
}
|
|
1168
|
+
GlassOptions resolvedGlassOptions = glassOptions == null ? GlassOptions.defaults() : glassOptions;
|
|
1169
|
+
if (!resolvedGlassOptions.isLiquidGlass()) {
|
|
1170
|
+
hideGlassBackground(backdrop, surface);
|
|
1171
|
+
container.setBackground(chromeBackgroundDrawable(background, cornerRadius));
|
|
1172
|
+
return;
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
container.setBackgroundColor(Color.TRANSPARENT);
|
|
1176
|
+
int surfaceColor = glassSurfaceColor(background, resolvedGlassOptions);
|
|
1177
|
+
if (surface != null) {
|
|
1178
|
+
surface.setBackground(chromeBackgroundDrawable(surfaceColor, cornerRadius));
|
|
1179
|
+
surface.setVisibility(View.VISIBLE);
|
|
1180
|
+
}
|
|
1181
|
+
if (backdrop != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
1182
|
+
View webView = getBridge() == null ? null : getBridge().getWebView();
|
|
1183
|
+
backdrop.configure(webView, dp(resolvedGlassOptions.blurRadiusDp), surfaceColor);
|
|
1184
|
+
backdrop.setVisibility(View.VISIBLE);
|
|
1185
|
+
} else if (backdrop != null) {
|
|
1186
|
+
backdrop.clearEffect();
|
|
1187
|
+
backdrop.setVisibility(View.GONE);
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
private void hideGlassBackground(GlassBackdropView backdrop, View surface) {
|
|
1192
|
+
if (backdrop != null) {
|
|
1193
|
+
backdrop.clearEffect();
|
|
1194
|
+
backdrop.setVisibility(View.GONE);
|
|
1195
|
+
}
|
|
1196
|
+
if (surface != null) {
|
|
1197
|
+
surface.setBackground(null);
|
|
1198
|
+
surface.setVisibility(View.GONE);
|
|
1078
1199
|
}
|
|
1079
1200
|
}
|
|
1080
1201
|
|
|
1202
|
+
private Drawable chromeBackgroundDrawable(int color, float cornerRadius) {
|
|
1203
|
+
GradientDrawable drawable = new GradientDrawable();
|
|
1204
|
+
drawable.setColor(color);
|
|
1205
|
+
if (cornerRadius > 0f) {
|
|
1206
|
+
drawable.setCornerRadius(cornerRadius);
|
|
1207
|
+
}
|
|
1208
|
+
return drawable;
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
private int glassSurfaceColor(int background, GlassOptions glassOptions) {
|
|
1212
|
+
return withAlpha(background, Math.round(Color.alpha(background) * (float) glassOptions.surfaceAlpha));
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1081
1215
|
private int parseColor(String value, int fallback) {
|
|
1082
1216
|
if (value == null || value.isEmpty()) {
|
|
1083
1217
|
return fallback;
|
|
@@ -1141,6 +1275,91 @@ public class NativeNavigationPlugin extends Plugin {
|
|
|
1141
1275
|
return mode == Configuration.UI_MODE_NIGHT_YES;
|
|
1142
1276
|
}
|
|
1143
1277
|
|
|
1278
|
+
private void fillContainer(View view) {
|
|
1279
|
+
if (view != null) {
|
|
1280
|
+
view.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
private boolean isLiquidGlassTabbar() {
|
|
1285
|
+
return tabbarGlassOptions != null && tabbarGlassOptions.isLiquidGlass();
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
private int tabbarHeight() {
|
|
1289
|
+
return dp(isLiquidGlassTabbar() ? LIQUID_GLASS_TABBAR_DP : DEFAULT_TABBAR_DP);
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
private float tabbarCornerRadius() {
|
|
1293
|
+
return tabbarHeight() / 2f;
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
private int tabbarWidth(int rootWidth) {
|
|
1297
|
+
if (isLiquidGlassTabbar()) {
|
|
1298
|
+
return Math.min(Math.max(0, rootWidth - dp(LIQUID_GLASS_TABBAR_SIDE_MARGIN_DP * 2)), dp(LIQUID_GLASS_TABBAR_MAX_WIDTH_DP));
|
|
1299
|
+
}
|
|
1300
|
+
return Math.min(Math.max(0, rootWidth - dp(48)), dp(420));
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
private int floatingTabbarBottomMargin(int navigationInset) {
|
|
1304
|
+
if (isLiquidGlassTabbar()) {
|
|
1305
|
+
return Math.max(dp(LIQUID_GLASS_TABBAR_FLOATING_BOTTOM_GAP_DP), navigationInset);
|
|
1306
|
+
}
|
|
1307
|
+
return navigationInset + dp(TABBAR_FLOATING_BOTTOM_GAP_DP);
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
private void applyTabbarMetrics(BottomNavigationView nativeTabbar) {
|
|
1311
|
+
boolean liquidGlass = isLiquidGlassTabbar();
|
|
1312
|
+
nativeTabbar.setMinimumHeight(tabbarHeight());
|
|
1313
|
+
nativeTabbar.setPadding(0, liquidGlass ? dp(LIQUID_GLASS_TABBAR_CONTENT_TOP_PADDING_DP) : 0, 0, 0);
|
|
1314
|
+
nativeTabbar.setItemPaddingTop(dp(liquidGlass ? LIQUID_GLASS_TABBAR_ITEM_VERTICAL_PADDING_DP : TABBAR_ITEM_VERTICAL_PADDING_DP));
|
|
1315
|
+
nativeTabbar.setItemPaddingBottom(dp(liquidGlass ? LIQUID_GLASS_TABBAR_ITEM_VERTICAL_PADDING_DP : TABBAR_ITEM_VERTICAL_PADDING_DP));
|
|
1316
|
+
nativeTabbar.setItemActiveIndicatorHeight(dp(liquidGlass ? LIQUID_GLASS_TABBAR_INDICATOR_DP : TABBAR_INDICATOR_DP));
|
|
1317
|
+
nativeTabbar.setActiveIndicatorLabelPadding(
|
|
1318
|
+
dp(liquidGlass ? LIQUID_GLASS_TABBAR_INDICATOR_LABEL_PADDING_DP : TABBAR_INDICATOR_LABEL_PADDING_DP)
|
|
1319
|
+
);
|
|
1320
|
+
alignTabbarMenu(nativeTabbar, liquidGlass);
|
|
1321
|
+
nativeTabbar.post(() -> alignTabbarMenu(nativeTabbar, isLiquidGlassTabbar()));
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
private void alignTabbarMenu(BottomNavigationView nativeTabbar, boolean liquidGlass) {
|
|
1325
|
+
nativeTabbar.setClipChildren(false);
|
|
1326
|
+
nativeTabbar.setClipToPadding(false);
|
|
1327
|
+
if (nativeTabbar.getChildCount() == 0) {
|
|
1328
|
+
return;
|
|
1329
|
+
}
|
|
1330
|
+
View menuView = nativeTabbar.getChildAt(0);
|
|
1331
|
+
ViewGroup.LayoutParams currentParams = menuView.getLayoutParams();
|
|
1332
|
+
FrameLayout.LayoutParams menuParams =
|
|
1333
|
+
currentParams instanceof FrameLayout.LayoutParams
|
|
1334
|
+
? (FrameLayout.LayoutParams) currentParams
|
|
1335
|
+
: new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
|
|
1336
|
+
menuParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
|
|
1337
|
+
menuParams.height = liquidGlass ? ViewGroup.LayoutParams.MATCH_PARENT : ViewGroup.LayoutParams.WRAP_CONTENT;
|
|
1338
|
+
menuParams.gravity = liquidGlass ? Gravity.CENTER : Gravity.TOP;
|
|
1339
|
+
menuView.setLayoutParams(menuParams);
|
|
1340
|
+
menuView.setTranslationY(liquidGlass ? dp(LIQUID_GLASS_TABBAR_CONTENT_TRANSLATION_Y_DP) : 0f);
|
|
1341
|
+
if (menuView instanceof ViewGroup) {
|
|
1342
|
+
ViewGroup menuGroup = (ViewGroup) menuView;
|
|
1343
|
+
menuGroup.setClipChildren(false);
|
|
1344
|
+
menuGroup.setClipToPadding(false);
|
|
1345
|
+
translateTabbarLabels(menuGroup, liquidGlass ? dp(LIQUID_GLASS_TABBAR_LABEL_TRANSLATION_Y_DP) : 0f);
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
private void translateTabbarLabels(View view, float translationY) {
|
|
1350
|
+
if (view instanceof TextView) {
|
|
1351
|
+
view.setTranslationY(translationY);
|
|
1352
|
+
return;
|
|
1353
|
+
}
|
|
1354
|
+
if (!(view instanceof ViewGroup)) {
|
|
1355
|
+
return;
|
|
1356
|
+
}
|
|
1357
|
+
ViewGroup group = (ViewGroup) view;
|
|
1358
|
+
for (int index = 0; index < group.getChildCount(); index++) {
|
|
1359
|
+
translateTabbarLabels(group.getChildAt(index), translationY);
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1144
1363
|
private void layoutChrome() {
|
|
1145
1364
|
FrameLayout root = contentRoot();
|
|
1146
1365
|
if (root == null) {
|
|
@@ -1149,8 +1368,8 @@ public class NativeNavigationPlugin extends Plugin {
|
|
|
1149
1368
|
int status = statusBarInset();
|
|
1150
1369
|
int bottom = navigationBarInset();
|
|
1151
1370
|
int navbarHeight = navbarVisible ? status + dp(DEFAULT_NAVBAR_DP) : 0;
|
|
1152
|
-
int tabbarHeight =
|
|
1153
|
-
int tabbarBottomMargin = tabbarVisible ? bottom
|
|
1371
|
+
int tabbarHeight = tabbarHeight();
|
|
1372
|
+
int tabbarBottomMargin = tabbarVisible ? floatingTabbarBottomMargin(bottom) : bottom;
|
|
1154
1373
|
|
|
1155
1374
|
if (navbarContainer != null) {
|
|
1156
1375
|
FrameLayout.LayoutParams containerParams = new FrameLayout.LayoutParams(
|
|
@@ -1159,6 +1378,8 @@ public class NativeNavigationPlugin extends Plugin {
|
|
|
1159
1378
|
Gravity.TOP
|
|
1160
1379
|
);
|
|
1161
1380
|
navbarContainer.setLayoutParams(containerParams);
|
|
1381
|
+
fillContainer(navbarGlassBackdrop);
|
|
1382
|
+
fillContainer(navbarGlassSurface);
|
|
1162
1383
|
FrameLayout.LayoutParams toolbarParams = new FrameLayout.LayoutParams(
|
|
1163
1384
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
1164
1385
|
dp(DEFAULT_NAVBAR_DP),
|
|
@@ -1170,7 +1391,7 @@ public class NativeNavigationPlugin extends Plugin {
|
|
|
1170
1391
|
|
|
1171
1392
|
if (tabbarContainer != null) {
|
|
1172
1393
|
int rootWidth = root.getWidth() > 0 ? root.getWidth() : Resources.getSystem().getDisplayMetrics().widthPixels;
|
|
1173
|
-
int tabbarWidth =
|
|
1394
|
+
int tabbarWidth = tabbarWidth(rootWidth);
|
|
1174
1395
|
FrameLayout.LayoutParams tabbarContainerParams = new FrameLayout.LayoutParams(
|
|
1175
1396
|
tabbarWidth,
|
|
1176
1397
|
tabbarHeight,
|
|
@@ -1178,18 +1399,23 @@ public class NativeNavigationPlugin extends Plugin {
|
|
|
1178
1399
|
);
|
|
1179
1400
|
tabbarContainerParams.bottomMargin = tabbarBottomMargin;
|
|
1180
1401
|
tabbarContainer.setLayoutParams(tabbarContainerParams);
|
|
1402
|
+
fillContainer(tabbarGlassBackdrop);
|
|
1403
|
+
fillContainer(tabbarGlassSurface);
|
|
1181
1404
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
1182
1405
|
tabbarContainer.invalidateOutline();
|
|
1406
|
+
tabbarGlassBackdrop.invalidateOutline();
|
|
1407
|
+
tabbarGlassSurface.invalidateOutline();
|
|
1183
1408
|
}
|
|
1184
1409
|
}
|
|
1185
1410
|
|
|
1186
1411
|
if (tabbar != null) {
|
|
1412
|
+
applyTabbarMetrics(tabbar);
|
|
1187
1413
|
FrameLayout.LayoutParams tabbarParams = new FrameLayout.LayoutParams(
|
|
1188
1414
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
1189
1415
|
ViewGroup.LayoutParams.MATCH_PARENT
|
|
1190
1416
|
);
|
|
1191
1417
|
tabbar.setLayoutParams(tabbarParams);
|
|
1192
|
-
tabbar.setPadding(0, 0, 0, 0);
|
|
1418
|
+
tabbar.setPadding(0, isLiquidGlassTabbar() ? dp(LIQUID_GLASS_TABBAR_CONTENT_TOP_PADDING_DP) : 0, 0, 0);
|
|
1193
1419
|
}
|
|
1194
1420
|
|
|
1195
1421
|
bringChromeToFront();
|
|
@@ -1245,14 +1471,15 @@ public class NativeNavigationPlugin extends Plugin {
|
|
|
1245
1471
|
}
|
|
1246
1472
|
|
|
1247
1473
|
private JSObject currentInsets() {
|
|
1248
|
-
int
|
|
1249
|
-
int
|
|
1474
|
+
int navbarHeight = navbarVisible ? statusBarInset() + dp(DEFAULT_NAVBAR_DP) : 0;
|
|
1475
|
+
int top = navbarVisible ? navbarHeight : 0;
|
|
1476
|
+
int bottom = tabbarVisible ? floatingTabbarBottomMargin(navigationBarInset()) + tabbarHeight() : 0;
|
|
1250
1477
|
JSObject insets = new JSObject();
|
|
1251
1478
|
insets.put("top", top);
|
|
1252
1479
|
insets.put("right", 0);
|
|
1253
1480
|
insets.put("bottom", bottom);
|
|
1254
1481
|
insets.put("left", 0);
|
|
1255
|
-
insets.put("navbarHeight",
|
|
1482
|
+
insets.put("navbarHeight", navbarHeight);
|
|
1256
1483
|
insets.put("tabbarHeight", bottom);
|
|
1257
1484
|
return insets;
|
|
1258
1485
|
}
|
|
@@ -1307,7 +1534,10 @@ public class NativeNavigationPlugin extends Plugin {
|
|
|
1307
1534
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
1308
1535
|
WindowInsets insets = getActivity().getWindow().getDecorView().getRootWindowInsets();
|
|
1309
1536
|
if (insets != null) {
|
|
1310
|
-
|
|
1537
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
|
1538
|
+
return insets.getInsets(WindowInsets.Type.navigationBars()).bottom;
|
|
1539
|
+
}
|
|
1540
|
+
return insets.getSystemWindowInsetBottom();
|
|
1311
1541
|
}
|
|
1312
1542
|
}
|
|
1313
1543
|
return systemDimension("navigation_bar_height");
|
|
@@ -1322,6 +1552,208 @@ public class NativeNavigationPlugin extends Plugin {
|
|
|
1322
1552
|
return Math.round(value * getContext().getResources().getDisplayMetrics().density);
|
|
1323
1553
|
}
|
|
1324
1554
|
|
|
1555
|
+
private float dp(double value) {
|
|
1556
|
+
return (float) (value * getContext().getResources().getDisplayMetrics().density);
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
private static final class GlassOptions {
|
|
1560
|
+
|
|
1561
|
+
private static final String EFFECT_NONE = "none";
|
|
1562
|
+
private static final String EFFECT_LIQUID_GLASS = "liquidGlass";
|
|
1563
|
+
private static final double DEFAULT_BLUR_RADIUS_DP = 18d;
|
|
1564
|
+
private static final double DEFAULT_SURFACE_ALPHA = 0.62d;
|
|
1565
|
+
|
|
1566
|
+
final String effect;
|
|
1567
|
+
final double blurRadiusDp;
|
|
1568
|
+
final double surfaceAlpha;
|
|
1569
|
+
|
|
1570
|
+
GlassOptions(String effect, double blurRadiusDp, double surfaceAlpha) {
|
|
1571
|
+
this.effect = effect;
|
|
1572
|
+
this.blurRadiusDp = Math.max(0d, blurRadiusDp);
|
|
1573
|
+
this.surfaceAlpha = Math.max(0d, Math.min(1d, surfaceAlpha));
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1576
|
+
static GlassOptions defaults() {
|
|
1577
|
+
return new GlassOptions(EFFECT_NONE, DEFAULT_BLUR_RADIUS_DP, DEFAULT_SURFACE_ALPHA);
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
static GlassOptions from(JSObject raw, GlassOptions fallback) {
|
|
1581
|
+
GlassOptions base = fallback == null ? defaults() : fallback;
|
|
1582
|
+
if (raw == null) {
|
|
1583
|
+
return base;
|
|
1584
|
+
}
|
|
1585
|
+
|
|
1586
|
+
String effect = raw.optString("effect", base.effect);
|
|
1587
|
+
if (!EFFECT_NONE.equals(effect) && !EFFECT_LIQUID_GLASS.equals(effect)) {
|
|
1588
|
+
effect = base.effect;
|
|
1589
|
+
}
|
|
1590
|
+
double blurRadiusDp = raw.has("blurRadius") ? raw.optDouble("blurRadius", base.blurRadiusDp) : base.blurRadiusDp;
|
|
1591
|
+
double surfaceAlpha = raw.has("surfaceAlpha") ? raw.optDouble("surfaceAlpha", base.surfaceAlpha) : base.surfaceAlpha;
|
|
1592
|
+
return new GlassOptions(effect, blurRadiusDp, surfaceAlpha);
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
boolean isLiquidGlass() {
|
|
1596
|
+
return EFFECT_LIQUID_GLASS.equals(effect);
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1600
|
+
private static final class GlassBackdropView extends View {
|
|
1601
|
+
|
|
1602
|
+
private static final long SOURCE_CONTENT_REFRESH_INTERVAL_MS = 250L;
|
|
1603
|
+
|
|
1604
|
+
private final Paint fallbackPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
|
1605
|
+
private final int[] sourceLocation = new int[2];
|
|
1606
|
+
private final int[] viewLocation = new int[2];
|
|
1607
|
+
private final ViewTreeObserver.OnScrollChangedListener sourceScrollListener = this::markDirty;
|
|
1608
|
+
private final ViewTreeObserver.OnPreDrawListener sourcePreDrawListener = () -> {
|
|
1609
|
+
markDirtyFromSourcePreDraw();
|
|
1610
|
+
return true;
|
|
1611
|
+
};
|
|
1612
|
+
private final View.OnLayoutChangeListener sourceLayoutListener = (
|
|
1613
|
+
view,
|
|
1614
|
+
left,
|
|
1615
|
+
top,
|
|
1616
|
+
right,
|
|
1617
|
+
bottom,
|
|
1618
|
+
oldLeft,
|
|
1619
|
+
oldTop,
|
|
1620
|
+
oldRight,
|
|
1621
|
+
oldBottom
|
|
1622
|
+
) -> markDirty();
|
|
1623
|
+
private View source;
|
|
1624
|
+
private int fallbackColor = Color.TRANSPARENT;
|
|
1625
|
+
private boolean dirty;
|
|
1626
|
+
private boolean redrawPending;
|
|
1627
|
+
private long lastSourcePreDrawRefreshMs;
|
|
1628
|
+
|
|
1629
|
+
GlassBackdropView(android.content.Context context) {
|
|
1630
|
+
super(context);
|
|
1631
|
+
setWillNotDraw(false);
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
void configure(View source, float blurRadiusPx, int fallbackColor) {
|
|
1635
|
+
this.fallbackColor = fallbackColor;
|
|
1636
|
+
attachSource(source);
|
|
1637
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
1638
|
+
Api31RenderEffects.setBlur(this, blurRadiusPx);
|
|
1639
|
+
}
|
|
1640
|
+
markDirty();
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1643
|
+
void clearEffect() {
|
|
1644
|
+
attachSource(null);
|
|
1645
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
1646
|
+
Api31RenderEffects.clear(this);
|
|
1647
|
+
}
|
|
1648
|
+
markDirty();
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1651
|
+
private void attachSource(View nextSource) {
|
|
1652
|
+
if (source == nextSource) {
|
|
1653
|
+
return;
|
|
1654
|
+
}
|
|
1655
|
+
if (source != null) {
|
|
1656
|
+
source.removeOnLayoutChangeListener(sourceLayoutListener);
|
|
1657
|
+
ViewTreeObserver observer = source.getViewTreeObserver();
|
|
1658
|
+
if (observer.isAlive()) {
|
|
1659
|
+
observer.removeOnScrollChangedListener(sourceScrollListener);
|
|
1660
|
+
observer.removeOnPreDrawListener(sourcePreDrawListener);
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1663
|
+
source = nextSource;
|
|
1664
|
+
if (source != null) {
|
|
1665
|
+
source.addOnLayoutChangeListener(sourceLayoutListener);
|
|
1666
|
+
ViewTreeObserver observer = source.getViewTreeObserver();
|
|
1667
|
+
if (observer.isAlive()) {
|
|
1668
|
+
observer.addOnScrollChangedListener(sourceScrollListener);
|
|
1669
|
+
observer.addOnPreDrawListener(sourcePreDrawListener);
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
markDirty();
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
private void markDirty() {
|
|
1676
|
+
dirty = true;
|
|
1677
|
+
scheduleRedrawIfVisible();
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1680
|
+
private void markDirtyFromSourcePreDraw() {
|
|
1681
|
+
dirty = true;
|
|
1682
|
+
long now = System.currentTimeMillis();
|
|
1683
|
+
if (now - lastSourcePreDrawRefreshMs < SOURCE_CONTENT_REFRESH_INTERVAL_MS) {
|
|
1684
|
+
return;
|
|
1685
|
+
}
|
|
1686
|
+
lastSourcePreDrawRefreshMs = now;
|
|
1687
|
+
scheduleRedrawIfVisible();
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1690
|
+
private void scheduleRedrawIfVisible() {
|
|
1691
|
+
if (redrawPending || getVisibility() != View.VISIBLE || !isShown()) {
|
|
1692
|
+
return;
|
|
1693
|
+
}
|
|
1694
|
+
redrawPending = true;
|
|
1695
|
+
postInvalidateOnAnimation();
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1698
|
+
@Override
|
|
1699
|
+
protected void onDraw(Canvas canvas) {
|
|
1700
|
+
super.onDraw(canvas);
|
|
1701
|
+
View currentSource = source;
|
|
1702
|
+
if (currentSource == null || currentSource.getWidth() <= 0 || currentSource.getHeight() <= 0) {
|
|
1703
|
+
fallbackPaint.setColor(fallbackColor);
|
|
1704
|
+
canvas.drawRect(0, 0, getWidth(), getHeight(), fallbackPaint);
|
|
1705
|
+
} else {
|
|
1706
|
+
currentSource.getLocationOnScreen(sourceLocation);
|
|
1707
|
+
getLocationOnScreen(viewLocation);
|
|
1708
|
+
canvas.save();
|
|
1709
|
+
canvas.translate(sourceLocation[0] - viewLocation[0], sourceLocation[1] - viewLocation[1]);
|
|
1710
|
+
currentSource.draw(canvas);
|
|
1711
|
+
canvas.restore();
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1714
|
+
dirty = false;
|
|
1715
|
+
redrawPending = false;
|
|
1716
|
+
}
|
|
1717
|
+
|
|
1718
|
+
@Override
|
|
1719
|
+
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
|
|
1720
|
+
super.onSizeChanged(width, height, oldWidth, oldHeight);
|
|
1721
|
+
if (width != oldWidth || height != oldHeight) {
|
|
1722
|
+
markDirty();
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
|
|
1726
|
+
@Override
|
|
1727
|
+
protected void onVisibilityChanged(View changedView, int visibility) {
|
|
1728
|
+
super.onVisibilityChanged(changedView, visibility);
|
|
1729
|
+
if (visibility != View.VISIBLE) {
|
|
1730
|
+
redrawPending = false;
|
|
1731
|
+
return;
|
|
1732
|
+
}
|
|
1733
|
+
if (dirty) {
|
|
1734
|
+
scheduleRedrawIfVisible();
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1739
|
+
@RequiresApi(Build.VERSION_CODES.S)
|
|
1740
|
+
private static final class Api31RenderEffects {
|
|
1741
|
+
|
|
1742
|
+
static void setBlur(View view, float blurRadiusPx) {
|
|
1743
|
+
if (blurRadiusPx <= 0f) {
|
|
1744
|
+
view.setRenderEffect(null);
|
|
1745
|
+
return;
|
|
1746
|
+
}
|
|
1747
|
+
view.setRenderEffect(
|
|
1748
|
+
android.graphics.RenderEffect.createBlurEffect(blurRadiusPx, blurRadiusPx, android.graphics.Shader.TileMode.CLAMP)
|
|
1749
|
+
);
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1752
|
+
static void clear(View view) {
|
|
1753
|
+
view.setRenderEffect(null);
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
|
|
1325
1757
|
private void runOnUiThread(Runnable runnable) {
|
|
1326
1758
|
Activity activity = getActivity();
|
|
1327
1759
|
if (activity == null) {
|