diff --git a/android/app/build.gradle b/android/app/build.gradle
index 329e94262ca..5001d56add3 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -35,6 +35,7 @@ repositories {
dependencies {
compile fileTree(dir: "libs", include: ["*.jar"])
+ compile "com.aurelhubert:ahbottomnavigation:1.2.3"
compile "com.android.support:appcompat-v7:23.0.1"
compile 'com.android.support:design:23.1.1'
compile "com.facebook.react:react-native:+" // From node_modules
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index db7d918eb97..811664cca20 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -3,6 +3,7 @@
+
diff --git a/android/app/src/main/java/com/reactnativenavigation/activities/BaseReactActivity.java b/android/app/src/main/java/com/reactnativenavigation/activities/BaseReactActivity.java
index 34cbea43f1a..583da7f7c21 100644
--- a/android/app/src/main/java/com/reactnativenavigation/activities/BaseReactActivity.java
+++ b/android/app/src/main/java/com/reactnativenavigation/activities/BaseReactActivity.java
@@ -135,6 +135,7 @@ protected ReactRootView createRootView() {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ ContextProvider.setActivityContext(this);
mReactInstanceManager = createReactInstanceManager();
handleOnCreate();
}
diff --git a/android/app/src/main/java/com/reactnativenavigation/activities/BottomTabActivity.java b/android/app/src/main/java/com/reactnativenavigation/activities/BottomTabActivity.java
new file mode 100644
index 00000000000..f0a703f6682
--- /dev/null
+++ b/android/app/src/main/java/com/reactnativenavigation/activities/BottomTabActivity.java
@@ -0,0 +1,182 @@
+package com.reactnativenavigation.activities;
+
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.view.Menu;
+import android.widget.FrameLayout;
+
+import com.aurelhubert.ahbottomnavigation.AHBottomNavigation;
+import com.aurelhubert.ahbottomnavigation.AHBottomNavigationItem;
+import com.reactnativenavigation.R;
+import com.reactnativenavigation.core.RctManager;
+import com.reactnativenavigation.core.objects.Screen;
+import com.reactnativenavigation.views.RnnToolBar;
+import com.reactnativenavigation.views.ScreenStack;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+
+/**
+ * Created by guyc on 02/04/16.
+ */
+public class BottomTabActivity extends BaseReactActivity implements AHBottomNavigation.OnTabSelectedListener {
+ public static final String EXTRA_SCREENS = "extraScreens";
+
+ private static final String TAB_STYLE_BUTTON_COLOR = "tabBarButtonColor";
+ private static final String TAB_STYLE_SELECTED_COLOR = "tabBarSelectedButtonColor";
+ private static final String TAB_STYLE_BAR_BG_COLOR = "tabBarBackgroundColor";
+ private static final String TAB_STYLE_INACTIVE_TITLES = "tabShowInactiveTitles";
+
+ private static int DEFAULT_TAB_BAR_BG_COLOR = 0xFFFFFFFF;
+ private static int DEFAULT_TAB_BUTTON_COLOR = Color.GRAY;
+ private static int DEFAULT_TAB_SELECTED_COLOR = 0xFF0000FF;
+ private static boolean DEFAULT_TAB_INACTIVE_TITLES = true;
+
+ private AHBottomNavigation mBottomNavigation;
+ private FrameLayout mContentFrame;
+ private ArrayList mScreenStacks;
+ private int mCurrentStackPosition = 0;
+
+ @Override
+ protected void handleOnCreate() {
+ mReactInstanceManager = RctManager.getInstance().getReactInstanceManager();
+
+ setContentView(R.layout.bottom_tab_activity);
+ mToolbar = (RnnToolBar) findViewById(R.id.toolbar);
+ mBottomNavigation = (AHBottomNavigation) findViewById(R.id.bottom_tab_bar);
+ mContentFrame = (FrameLayout) findViewById(R.id.contentFrame);
+
+ ArrayList screens = (ArrayList) getIntent().getSerializableExtra(EXTRA_SCREENS);
+ mBottomNavigation.setForceTint(true);
+ setupToolbar(screens);
+ setupTabs(getIntent().getExtras());
+ setupPages(screens);
+ }
+
+ private void setupPages(ArrayList screens) {
+ new SetupTabsTask(this, screens).execute();
+ }
+
+ private void setupToolbar(ArrayList screens) {
+ Screen initialScreen = screens.get(0);
+ setNavigationStyle(initialScreen);
+ mToolbar.setScreens(screens);
+ mToolbar.setTitle(initialScreen.title);
+ setSupportActionBar(mToolbar);
+ }
+
+ @Override
+ public void setNavigationStyle(Screen screen) {
+ super.setNavigationStyle(screen);
+ mToolbar.setTitle(screen.title);
+ }
+
+ private void setupTabs(Bundle style) {
+
+ mBottomNavigation.setForceTitlesDisplay(style.getBoolean(TAB_STYLE_INACTIVE_TITLES, DEFAULT_TAB_INACTIVE_TITLES));
+ mBottomNavigation.setForceTint(true);
+ mBottomNavigation.setDefaultBackgroundColor(getColor(style, TAB_STYLE_BAR_BG_COLOR, DEFAULT_TAB_BAR_BG_COLOR));
+ mBottomNavigation.setInactiveColor(getColor(style, TAB_STYLE_BUTTON_COLOR, DEFAULT_TAB_BUTTON_COLOR));
+ mBottomNavigation.setAccentColor(getColor(style, TAB_STYLE_SELECTED_COLOR, DEFAULT_TAB_SELECTED_COLOR));
+ }
+
+ private static int getColor(Bundle bundle, String key, int defaultColor) {
+ if (bundle.containsKey(key)) {
+ return Color.parseColor(bundle.getString(key));
+ }
+ else {
+ return defaultColor;
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ boolean ret = super.onCreateOptionsMenu(menu);
+ mToolbar.handleOnCreateOptionsMenuAsync();
+ return ret;
+ }
+
+ @Override
+ public void push(Screen screen) {
+ super.push(screen);
+ mScreenStacks.get(mCurrentStackPosition).push(screen);
+ }
+
+ @Override
+ public Screen pop(String navigatorId) {
+ super.pop(navigatorId);
+ Screen screen = mScreenStacks.get(mCurrentStackPosition).pop();
+ setNavigationStyle(screen);
+ return screen;
+ }
+
+ @Override
+ protected Screen getCurrentScreen() {
+ return mScreenStacks.get(mCurrentStackPosition).peek();
+ }
+
+ @Override
+ protected String getCurrentNavigatorId() {
+ return mScreenStacks.get(mCurrentStackPosition).peek().navigatorId;
+ }
+
+ @Override
+ public int getScreenStackSize() {
+ return mScreenStacks.get(mCurrentStackPosition).getStackSize();
+ }
+
+ @Override
+ public void onTabSelected(int position, boolean wasSelected) {
+ if (wasSelected) {
+ return;
+ }
+ mContentFrame.removeAllViews();
+ mContentFrame.addView(mScreenStacks.get(position), new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+ mCurrentStackPosition = position;
+ setNavigationStyle(mScreenStacks.get(mCurrentStackPosition).peek());
+ }
+
+ private static class SetupTabsTask extends AsyncTask> {
+ private BottomTabActivity mActivity;
+ private ArrayList mScreens;
+
+ public SetupTabsTask(BottomTabActivity context, ArrayList screens) {
+ mActivity = context;
+ mScreens = screens;
+ }
+
+ @Override
+ protected Map doInBackground(Void... params) {
+ Map icons = new HashMap<>();
+ for (Screen screen : mScreens) {
+ if (screen.icon != null) {
+ icons.put(screen, screen.getIcon(this.mActivity));
+ }
+ }
+ return icons;
+ }
+
+ @Override
+ protected void onPostExecute(Map icons) {
+ mActivity.setTabsWithIcons(mScreens, icons);
+ }
+ }
+
+ private void setTabsWithIcons(ArrayList screens, Map icons) {
+ mScreenStacks = new ArrayList<>();
+ for(Screen screen: screens) {
+ ScreenStack stack = new ScreenStack(this);
+ stack.push(screen);
+ mScreenStacks.add(stack);
+ AHBottomNavigationItem item = new AHBottomNavigationItem(screen.label, icons.get(screen), Color.GRAY);
+ mBottomNavigation.addItem(item);
+ mBottomNavigation.setOnTabSelectedListener(this);
+ }
+ this.onTabSelected(0, false);
+ }
+}
diff --git a/android/app/src/main/java/com/reactnativenavigation/activities/TabActivity.java b/android/app/src/main/java/com/reactnativenavigation/activities/TabActivity.java
index 7209e786408..09f06b7f74b 100644
--- a/android/app/src/main/java/com/reactnativenavigation/activities/TabActivity.java
+++ b/android/app/src/main/java/com/reactnativenavigation/activities/TabActivity.java
@@ -42,6 +42,7 @@ private void setupToolbar(ArrayList screens) {
setNavigationStyle(initialScreen);
mToolbar.setScreens(screens);
mToolbar.setTitle(initialScreen.title);
+ mToolbar.setupToolbarButtonsAsync(initialScreen);
setSupportActionBar(mToolbar);
}
diff --git a/android/app/src/main/java/com/reactnativenavigation/core/objects/Button.java b/android/app/src/main/java/com/reactnativenavigation/core/objects/Button.java
index e464f187a0f..69abd12af9b 100644
--- a/android/app/src/main/java/com/reactnativenavigation/core/objects/Button.java
+++ b/android/app/src/main/java/com/reactnativenavigation/core/objects/Button.java
@@ -10,6 +10,7 @@
import com.facebook.react.bridge.ReadableMap;
import com.reactnativenavigation.BuildConfig;
+import com.reactnativenavigation.utils.IconUtils;
import com.reactnativenavigation.utils.ResourceDrawableIdHelper;
import java.io.Serializable;
@@ -24,13 +25,10 @@
public class Button extends JsonObject implements Serializable {
private static final long serialVersionUID = -570145217281069067L;
- public static final String LOCAL_RESOURCE_URI_SCHEME = "res";
private static final String KEY_ID = "id";
private static final String KEY_TITLE = "title";
private static final String KEY_ICON = "icon";
- private static ResourceDrawableIdHelper sResDrawableIdHelper = new ResourceDrawableIdHelper();
-
public String id;
public String title;
private String mIconSource;
@@ -49,47 +47,7 @@ public boolean hasIcon() {
}
public Drawable getIcon(Context ctx) {
- if (mIconSource == null) {
- return null;
- }
-
- try {
- Drawable icon;
- Uri iconUri = getIconUri(ctx);
-
- if (LOCAL_RESOURCE_URI_SCHEME.equals(iconUri.getScheme())) {
- icon = sResDrawableIdHelper.getResourceDrawable(ctx, mIconSource);
- } else {
- URL url = new URL(iconUri.toString());
- Bitmap bitmap = BitmapFactory.decodeStream(url.openStream());
- icon = new BitmapDrawable(bitmap);
- }
- return icon;
- } catch (Exception e) {
- if (BuildConfig.DEBUG) {
- e.printStackTrace();
- }
- }
- return null;
- }
-
- private Uri getIconUri(Context context) {
- Uri ret = null;
- if (mIconSource != null) {
- try {
- ret = Uri.parse(mIconSource);
- // Verify scheme is set, so that relative uri (used by static resources) are not handled.
- if (ret.getScheme() == null) {
- ret = null;
- }
- } catch (Exception e) {
- // Ignore malformed uri, then attempt to extract resource ID.
- }
- if (ret == null) {
- ret = sResDrawableIdHelper.getResourceDrawableUri(context, mIconSource);
- }
- }
- return ret;
+ return IconUtils.getIcon(ctx, mIconSource);
}
public int getItemId() {
diff --git a/android/app/src/main/java/com/reactnativenavigation/core/objects/Screen.java b/android/app/src/main/java/com/reactnativenavigation/core/objects/Screen.java
index c227f755472..7d1b87b88b8 100644
--- a/android/app/src/main/java/com/reactnativenavigation/core/objects/Screen.java
+++ b/android/app/src/main/java/com/reactnativenavigation/core/objects/Screen.java
@@ -1,5 +1,7 @@
package com.reactnativenavigation.core.objects;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@@ -7,6 +9,7 @@
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableNativeMap;
+import com.reactnativenavigation.utils.IconUtils;
import java.io.Serializable;
import java.util.ArrayList;
@@ -37,7 +40,7 @@ public class Screen extends JsonObject implements Serializable {
private static final String KEY_TAB_NORMAL_TEXT_COLOR = "tabNormalTextColor";
private static final String KEY_TAB_SELECTED_TEXT_COLOR = "tabSelectedTextColor";
private static final String KEY_TAB_INDICATOR_COLOR = "tabIndicatorColor";
- public static final String KEY_PROPS = "passProps";
+ private static final String KEY_PROPS = "passProps";
public final String title;
public final String label;
@@ -45,7 +48,7 @@ public class Screen extends JsonObject implements Serializable {
public final String screenInstanceId;
public final String navigatorId;
public final String navigatorEventId;
- public final int icon;
+ public final String icon;
public final ArrayList