Skip to content

Commit 86e22ce

Browse files
authored
Android: improve BottomNavigation (experimental feature) (#14126)
* xml test * badge * use old tabgroup layout * theme * more features * more colors * touchfeedback * res icons * add addTab() * remove redundant code, floating bar * icon font support * tintColor support for icons * optimize selected state * color updates * add flags * status bar * chore: apidoc * update property * events * test, bugfix for empty title * add enabled property * docs * fix WindowProxy * fix WindowProxy * fix linting * add back windowFlags for light status bar * docs: fix version number
1 parent ea4dbb2 commit 86e22ce

File tree

14 files changed

+983
-13
lines changed

14 files changed

+983
-13
lines changed

android/modules/android/src/java/ti/modules/titanium/android/AndroidModule.java

+3
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,9 @@ public class AndroidModule extends KrollModule
363363
@Kroll.constant
364364
public static final int FLAG_UPDATE_CURRENT = PendingIntent.FLAG_UPDATE_CURRENT;
365365

366+
@Kroll.constant
367+
public static final int STATUS_BAR_LIGHT = 8192;
368+
366369
@Kroll.constant
367370
public static final int RESULT_OK = Activity.RESULT_OK;
368371
@Kroll.constant
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:layout_width="match_parent"
4+
android:layout_height="match_parent">
5+
6+
<FrameLayout
7+
android:id="@+id/bottomNavBar_content"
8+
android:layout_width="match_parent"
9+
android:layout_height="match_parent"
10+
android:layout_above="@+id/bottomNavBar" />
11+
12+
<com.google.android.material.bottomnavigation.BottomNavigationView
13+
android:id="@+id/bottomNavBar"
14+
android:layout_width="match_parent"
15+
android:layout_height="wrap_content"
16+
android:layout_alignParentBottom="true" />
17+
18+
</RelativeLayout>

android/modules/ui/src/java/ti/modules/titanium/ui/TabGroupProxy.java

+64-2
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,14 @@
66
*/
77
package ti.modules.titanium.ui;
88

9+
import static ti.modules.titanium.android.AndroidModule.STATUS_BAR_LIGHT;
10+
911
import android.app.Activity;
1012
import android.content.Intent;
13+
import android.os.Build;
1114
import android.os.Bundle;
1215
import android.view.LayoutInflater;
16+
import android.view.View;
1317

1418
import androidx.annotation.NonNull;
1519
import androidx.appcompat.app.ActionBar;
@@ -29,6 +33,7 @@
2933
import org.appcelerator.titanium.TiRootActivity;
3034
import org.appcelerator.titanium.proxy.ActivityProxy;
3135
import org.appcelerator.titanium.proxy.TiWindowProxy;
36+
import org.appcelerator.titanium.util.TiColorHelper;
3237
import org.appcelerator.titanium.util.TiConvert;
3338
import org.appcelerator.titanium.util.TiRHelper;
3439
import org.appcelerator.titanium.util.TiUIHelper;
@@ -39,6 +44,7 @@
3944

4045
import ti.modules.titanium.ui.android.AndroidModule;
4146
import ti.modules.titanium.ui.widget.tabgroup.TiUIAbstractTabGroup;
47+
import ti.modules.titanium.ui.widget.tabgroup.TiUIBottomNavigation;
4248
import ti.modules.titanium.ui.widget.tabgroup.TiUIBottomNavigationTabGroup;
4349
import ti.modules.titanium.ui.widget.tabgroup.TiUITabLayoutTabGroup;
4450

@@ -49,7 +55,8 @@
4955
TiC.PROPERTY_SWIPEABLE,
5056
TiC.PROPERTY_AUTO_TAB_TITLE,
5157
TiC.PROPERTY_EXIT_ON_CLOSE,
52-
TiC.PROPERTY_SMOOTH_SCROLL_ON_TAB_CLICK
58+
TiC.PROPERTY_SMOOTH_SCROLL_ON_TAB_CLICK,
59+
TiC.PROPERTY_INDICATOR_COLOR
5360
})
5461
public class TabGroupProxy extends TiWindowProxy implements TiActivityWindow
5562
{
@@ -69,6 +76,7 @@ public class TabGroupProxy extends TiWindowProxy implements TiActivityWindow
6976
private Object selectedTab; // NOTE: Can be TabProxy or Number
7077
private String tabGroupTitle = null;
7178
private boolean autoTabTitle = false;
79+
private boolean tabEnabled = true;
7280

7381
public TabGroupProxy()
7482
{
@@ -189,6 +197,22 @@ public void setActiveTab(Object tabOrIndex)
189197
}
190198
}
191199

200+
@Kroll.setProperty
201+
public void setEnabled(Boolean enabled)
202+
{
203+
tabEnabled = enabled;
204+
TiUIAbstractTabGroup tabGroup = (TiUIAbstractTabGroup) view;
205+
if (tabGroup != null) {
206+
tabGroup.setEnabled(enabled);
207+
}
208+
}
209+
210+
@Kroll.getProperty
211+
public Boolean getEnabled()
212+
{
213+
return tabEnabled;
214+
}
215+
192216
private TabProxy getActiveTabProxy()
193217
{
194218
Object activeTab = getActiveTab();
@@ -279,6 +303,9 @@ public void handleCreationDict(KrollDict options)
279303
if (options.containsKeyAndNotNull(TiC.PROPERTY_ACTIVE_TAB)) {
280304
setActiveTab(options.get(TiC.PROPERTY_ACTIVE_TAB));
281305
}
306+
if (options.containsKeyAndNotNull(TiC.PROPERTY_ENABLED)) {
307+
setEnabled(options.getBoolean(TiC.PROPERTY_ENABLED));
308+
}
282309
}
283310

284311
@Kroll.getProperty
@@ -323,6 +350,21 @@ protected void handleOpen(KrollDict options)
323350
if (topActivity == null || topActivity.isFinishing()) {
324351
return;
325352
}
353+
354+
// set theme for XML layout
355+
if (hasProperty(TiC.PROPERTY_STYLE)
356+
&& ((Integer) getProperty(TiC.PROPERTY_STYLE)) == AndroidModule.TABS_STYLE_BOTTOM_NAVIGATION
357+
&& getProperty(TiC.PROPERTY_THEME) != null) {
358+
try {
359+
String themeName = getProperty(TiC.PROPERTY_THEME).toString();
360+
int theme = TiRHelper.getResource("style."
361+
+ themeName.replaceAll("[^A-Za-z0-9_]", "_"));
362+
topActivity.setTheme(theme);
363+
topActivity.getApplicationContext().setTheme(theme);
364+
} catch (Exception e) {
365+
}
366+
}
367+
326368
Intent intent = new Intent(topActivity, TiActivity.class);
327369
fillIntent(topActivity, intent);
328370

@@ -367,7 +409,11 @@ public void windowCreated(TiBaseActivity activity, Bundle savedInstanceState)
367409
((TiUITabLayoutTabGroup) view).setTabMode((Integer) getProperty(TiC.PROPERTY_TAB_MODE));
368410
}
369411
} else {
370-
view = new TiUIBottomNavigationTabGroup(this, activity);
412+
if (TiConvert.toBoolean(getProperty("experimental"), false)) {
413+
view = new TiUIBottomNavigation(this, activity);
414+
} else {
415+
view = new TiUIBottomNavigationTabGroup(this, activity);
416+
}
371417
}
372418
// If we have set a title before the creation of the native view, set it now.
373419
if (this.tabGroupTitle != null) {
@@ -405,6 +451,22 @@ public void windowCreated(TiBaseActivity activity, Bundle savedInstanceState)
405451

406452
// Need to handle the cached activity proxy properties in the JS side.
407453
callPropertySync(PROPERTY_POST_TAB_GROUP_CREATED, null);
454+
455+
if (getActivity() != null) {
456+
if (hasPropertyAndNotNull(TiC.PROPERTY_FLAGS)) {
457+
if (TiConvert.toInt(getProperty(TiC.PROPERTY_FLAGS)) == STATUS_BAR_LIGHT
458+
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
459+
getActivity().getWindow().getDecorView()
460+
.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
461+
}
462+
}
463+
if (hasPropertyAndNotNull(TiC.PROPERTY_STATUS_BAR_COLOR)) {
464+
int colorInt = TiColorHelper.parseColor(
465+
TiConvert.toString(getProperty(TiC.PROPERTY_STATUS_BAR_COLOR)),
466+
TiApplication.getAppRootOrCurrentActivity());
467+
getActivity().getWindow().setStatusBarColor(colorInt);
468+
}
469+
}
408470
}
409471

410472
@Override

android/modules/ui/src/java/ti/modules/titanium/ui/WindowProxy.java

+10
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@
77

88
package ti.modules.titanium.ui;
99

10+
import static ti.modules.titanium.android.AndroidModule.STATUS_BAR_LIGHT;
11+
1012
import android.annotation.SuppressLint;
1113
import android.app.Activity;
1214
import android.content.Intent;
1315
import android.graphics.Color;
1416
import android.graphics.PixelFormat;
1517
import android.graphics.drawable.ColorDrawable;
1618
import android.graphics.drawable.Drawable;
19+
import android.os.Build;
1720
import android.os.Bundle;
1821
import android.os.Message;
1922
import android.text.Spannable;
@@ -333,6 +336,13 @@ public void windowCreated(TiBaseActivity activity, Bundle savedInstanceState)
333336
win.getDecorView().setSystemUiVisibility(TiConvert.toInt(getProperty(TiC.PROPERTY_UI_FLAGS)));
334337
}
335338

339+
if (hasProperty(TiC.PROPERTY_WINDOW_FLAGS)) {
340+
if ((TiConvert.toInt(getProperty(TiC.PROPERTY_WINDOW_FLAGS)) & STATUS_BAR_LIGHT) != 0
341+
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
342+
win.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
343+
}
344+
}
345+
336346
// Handle titleAttributes property.
337347
if (hasProperty(TiC.PROPERTY_TITLE_ATTRIBUTES)) {
338348
KrollDict innerAttributes = getProperties().getKrollDict(TiC.PROPERTY_TITLE_ATTRIBUTES);

android/modules/ui/src/java/ti/modules/titanium/ui/widget/tabgroup/TiUIAbstractTabGroup.java

+27-2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import org.appcelerator.titanium.proxy.TiWindowProxy;
4141
import org.appcelerator.titanium.util.TiColorHelper;
4242
import org.appcelerator.titanium.util.TiConvert;
43+
import org.appcelerator.titanium.util.TiIconDrawable;
4344
import org.appcelerator.titanium.util.TiUIHelper;
4445
import org.appcelerator.titanium.view.TiInsetsProvider;
4546
import org.appcelerator.titanium.view.TiUIView;
@@ -115,6 +116,13 @@ public abstract class TiUIAbstractTabGroup extends TiUIView
115116
*/
116117
public abstract void updateTabBackgroundDrawable(int index);
117118

119+
/**
120+
* Material 3 active indicator color
121+
*
122+
* @param color color
123+
*/
124+
public abstract void updateActiveIndicatorColor(int color);
125+
118126
/**
119127
* Update the tab's title to the proper text.
120128
*
@@ -144,6 +152,13 @@ public abstract class TiUIAbstractTabGroup extends TiUIView
144152
*/
145153
public abstract String getTabTitle(int index);
146154

155+
/**
156+
* Enables/disables tab menu
157+
*
158+
* @param enabled value
159+
*/
160+
public abstract void setEnabled(Boolean enabled);
161+
147162
// region protected fields
148163
protected final static String TAG = "TiUIAbstractTabGroup";
149164
protected static final String WARNING_LAYOUT_MESSAGE =
@@ -454,7 +469,7 @@ public void onPageScrollStateChanged(int i)
454469
// Set action bar color.
455470
if (proxy != null) {
456471
final ActionBar actionBar = ((AppCompatActivity) proxy.getActivity()).getSupportActionBar();
457-
if (actionBar != null) {
472+
if (actionBar != null && !this.tabs.isEmpty()) {
458473
final TiWindowProxy windowProxy = ((TabProxy) this.tabs.get(tabIndex).getProxy()).getWindow();
459474
final KrollDict windowProperties = windowProxy.getProperties();
460475
final KrollDict properties = getProxy().getProperties();
@@ -495,6 +510,9 @@ public void processProperties(KrollDict d)
495510
} else {
496511
setBackgroundColor(getDefaultBackgroundColor());
497512
}
513+
if (d.containsKeyAndNotNull(TiC.PROPERTY_INDICATOR_COLOR)) {
514+
updateActiveIndicatorColor(TiConvert.toColor(d, TiC.PROPERTY_INDICATOR_COLOR, proxy.getActivity()));
515+
}
498516
super.processProperties(d);
499517
}
500518

@@ -516,6 +534,8 @@ public void propertyChanged(String key, Object oldValue, Object newValue, KrollP
516534
for (TiUITab tabView : tabs) {
517535
updateTabBackgroundDrawable(tabs.indexOf(tabView));
518536
}
537+
} else if (key.equals(TiC.PROPERTY_INDICATOR_COLOR)) {
538+
updateActiveIndicatorColor(TiColorHelper.parseColor(newValue.toString(), proxy.getActivity()));
519539
} else {
520540
super.propertyChanged(key, oldValue, newValue, proxy);
521541
}
@@ -552,7 +572,12 @@ public Drawable updateIconTint(TiViewProxy tabProxy, Drawable drawable, boolean
552572
}
553573

554574
// Clone existing drawable so color filter applies correctly.
555-
drawable = drawable.getConstantState().newDrawable();
575+
if (drawable.getConstantState() == null && drawable.getClass() == TiIconDrawable.class) {
576+
// TiIconDrawable
577+
drawable = drawable.mutate();
578+
} else {
579+
drawable = drawable.getConstantState().newDrawable();
580+
}
556581

557582
final KrollDict tabProperties = tabProxy.getProperties();
558583
final KrollDict properties = getProxy().getProperties();

0 commit comments

Comments
 (0)