Browse Source

Merge pull request #82 from the-mx-group/android_drawer

Android drawer implementation
Guy Carmeli 8 years ago
parent
commit
be2bc55209

+ 73
- 4
android/app/src/main/java/com/reactnativenavigation/activities/BaseReactActivity.java View File

@@ -1,17 +1,21 @@
1 1
 package com.reactnativenavigation.activities;
2 2
 
3 3
 import android.content.Intent;
4
+import android.content.res.Configuration;
4 5
 import android.os.Build;
5 6
 import android.os.Bundle;
6 7
 import android.os.Handler;
7 8
 import android.provider.Settings;
8 9
 import android.support.annotation.CallSuper;
10
+import android.support.v4.widget.DrawerLayout;
11
+import android.support.v7.app.ActionBarDrawerToggle;
9 12
 import android.support.v7.app.AppCompatActivity;
10 13
 import android.util.Log;
11 14
 import android.view.KeyEvent;
12 15
 import android.view.Menu;
13 16
 import android.view.MenuItem;
14 17
 import android.widget.EditText;
18
+import android.widget.FrameLayout;
15 19
 import android.widget.Toast;
16 20
 
17 21
 import com.facebook.common.logging.FLog;
@@ -28,12 +32,14 @@ import com.reactnativenavigation.BuildConfig;
28 32
 import com.reactnativenavigation.controllers.ModalController;
29 33
 import com.reactnativenavigation.core.RctManager;
30 34
 import com.reactnativenavigation.core.objects.Button;
35
+import com.reactnativenavigation.core.objects.Drawer;
31 36
 import com.reactnativenavigation.core.objects.Screen;
32 37
 import com.reactnativenavigation.modal.RnnModal;
33 38
 import com.reactnativenavigation.packages.RnnPackage;
34 39
 import com.reactnativenavigation.utils.ContextProvider;
35 40
 import com.reactnativenavigation.utils.StyleHelper;
36 41
 import com.reactnativenavigation.views.RnnToolBar;
42
+import com.reactnativenavigation.views.ScreenStack;
37 43
 
38 44
 import java.util.Arrays;
39 45
 import java.util.List;
@@ -48,8 +54,10 @@ public abstract class BaseReactActivity extends AppCompatActivity implements Def
48 54
     protected static final String KEY_ANIMATED = "animated";
49 55
     protected static final String KEY_BADGE = "badge";
50 56
     protected static final String KEY_HIDDEN = "hidden";
57
+    protected static final String KEY_SIDE = "side";
51 58
     protected static final String KEY_TAB_INDEX = "tabIndex";
52 59
     protected static final String KEY_TITLE = "title";
60
+    protected static final String KEY_TO = "to";
53 61
     private static final String TAG = "BaseReactActivity";
54 62
     private static final String REDBOX_PERMISSION_MESSAGE =
55 63
             "Overlay permissions needs to be granted in order for react native apps to run in dev mode";
@@ -59,6 +67,9 @@ public abstract class BaseReactActivity extends AppCompatActivity implements Def
59 67
     private boolean mDoRefresh = false;
60 68
     private Menu mMenu;
61 69
     protected RnnToolBar mToolbar;
70
+    protected ActionBarDrawerToggle mDrawerToggle;
71
+    protected DrawerLayout mDrawerLayout;
72
+    protected ScreenStack mDrawerStack;
62 73
 
63 74
     /**
64 75
      * Returns the name of the bundle in assets. If this is null, and no file path is specified for
@@ -223,7 +234,7 @@ public abstract class BaseReactActivity extends AppCompatActivity implements Def
223 234
 
224 235
             if (getCurrentNavigatorId().equals(screen.navigatorId) &&
225 236
                 getScreenStackSize() >= 1) {
226
-                mToolbar.showBackButton(screen);
237
+                mToolbar.setNavUpButton(screen);
227 238
             }
228 239
         }
229 240
     }
@@ -233,15 +244,16 @@ public abstract class BaseReactActivity extends AppCompatActivity implements Def
233 244
         if (mToolbar != null &&
234 245
             getCurrentNavigatorId().equals(navigatorId) &&
235 246
             getScreenStackSize() <= 2) {
236
-            mToolbar.hideBackButton();
247
+            mToolbar.setNavUpButton();
237 248
         }
249
+
238 250
         return null;
239 251
     }
240 252
 
241 253
     @CallSuper
242 254
     public Screen popToRoot(String navigatorId) {
243 255
         if (mToolbar != null) {
244
-            mToolbar.hideBackButton();
256
+            mToolbar.setNavUpButton();
245 257
         }
246 258
 
247 259
         return null;
@@ -251,7 +263,7 @@ public abstract class BaseReactActivity extends AppCompatActivity implements Def
251 263
     public Screen resetTo(Screen screen) {
252 264
         StyleHelper.updateStyles(mToolbar, screen);
253 265
         if (mToolbar != null) {
254
-            mToolbar.hideBackButton();
266
+            mToolbar.setNavUpButton();
255 267
         }
256 268
 
257 269
         return null;
@@ -273,6 +285,14 @@ public abstract class BaseReactActivity extends AppCompatActivity implements Def
273 285
 
274 286
     public abstract int getScreenStackSize();
275 287
 
288
+    @Override
289
+    public void onConfigurationChanged(Configuration newConfig) {
290
+        super.onConfigurationChanged(newConfig);
291
+        if (mDrawerToggle != null) {
292
+            mDrawerToggle.onConfigurationChanged(newConfig);
293
+        }
294
+    }
295
+
276 296
     @Override
277 297
     public boolean onCreateOptionsMenu(Menu menu) {
278 298
         mMenu = menu;
@@ -285,6 +305,12 @@ public abstract class BaseReactActivity extends AppCompatActivity implements Def
285 305
 
286 306
     @Override
287 307
     public boolean onOptionsItemSelected(MenuItem item) {
308
+        if (mDrawerToggle != null &&
309
+            getScreenStackSize() == 1 &&
310
+            mDrawerToggle.onOptionsItemSelected(item)) {
311
+            return true;
312
+        }
313
+
288 314
         if (item.getItemId() == android.R.id.home) {
289 315
             onBackPressed();
290 316
         } else {
@@ -297,6 +323,14 @@ public abstract class BaseReactActivity extends AppCompatActivity implements Def
297 323
         return super.onOptionsItemSelected(item);
298 324
     }
299 325
 
326
+    @Override
327
+    public void onPostCreate(Bundle savedInstanceState) {
328
+        super.onPostCreate(savedInstanceState);
329
+        if (mDrawerToggle != null) {
330
+            mDrawerToggle.syncState();
331
+        }
332
+    }
333
+
300 334
     public Menu getMenu() {
301 335
         return mMenu;
302 336
     }
@@ -355,6 +389,20 @@ public abstract class BaseReactActivity extends AppCompatActivity implements Def
355 389
         super.onBackPressed();
356 390
     }
357 391
 
392
+    protected void setupDrawer(Screen screen, Drawer drawer, int drawerFrameId, int drawerLayoutId) {
393
+        if (drawer == null || drawer.left == null) {
394
+            return;
395
+        }
396
+
397
+        mDrawerStack = new ScreenStack(this);
398
+        FrameLayout drawerFrame = (FrameLayout) findViewById(drawerFrameId);
399
+        drawerFrame.addView(mDrawerStack);
400
+        mDrawerStack.push(drawer.left);
401
+
402
+        mDrawerLayout = (DrawerLayout) findViewById(drawerLayoutId);
403
+        mDrawerToggle = mToolbar.setupDrawer(mDrawerLayout, drawer.left, screen);
404
+    }
405
+
358 406
     public void setNavigationButtons(ReadableMap buttons){
359 407
         if (mToolbar == null) {
360 408
             return;
@@ -384,4 +432,25 @@ public abstract class BaseReactActivity extends AppCompatActivity implements Def
384 432
             mToolbar.showToolbar(animated);
385 433
         }
386 434
     }
435
+
436
+    public void toggleDrawer(ReadableMap params) {
437
+        if (mToolbar == null || mDrawerToggle == null) {
438
+            return;
439
+        }
440
+
441
+        boolean animated = params.getBoolean(KEY_ANIMATED);
442
+        String side = params.getString(KEY_SIDE);
443
+        String to = params.getString(KEY_TO);
444
+        switch (to) {
445
+            case "open":
446
+                mToolbar.showDrawer(animated);
447
+                break;
448
+            case "closed":
449
+                mToolbar.hideDrawer(animated);
450
+                break;
451
+            default:
452
+                mToolbar.toggleDrawer(animated);
453
+                break;
454
+        }
455
+    }
387 456
 }

+ 6
- 2
android/app/src/main/java/com/reactnativenavigation/activities/BottomTabActivity.java View File

@@ -12,6 +12,7 @@ import com.aurelhubert.ahbottomnavigation.AHBottomNavigationItem;
12 12
 import com.facebook.react.bridge.ReadableMap;
13 13
 import com.reactnativenavigation.R;
14 14
 import com.reactnativenavigation.core.RctManager;
15
+import com.reactnativenavigation.core.objects.Drawer;
15 16
 import com.reactnativenavigation.core.objects.Screen;
16 17
 import com.reactnativenavigation.utils.StyleHelper;
17 18
 import com.reactnativenavigation.views.RnnToolBar;
@@ -25,6 +26,7 @@ import java.util.Map;
25 26
  * Created by guyc on 02/04/16.
26 27
  */
27 28
 public class BottomTabActivity extends BaseReactActivity implements AHBottomNavigation.OnTabSelectedListener {
29
+    public static final String DRAWER_PARAMS = "drawerParams";
28 30
     public static final String EXTRA_SCREENS = "extraScreens";
29 31
 
30 32
     private static final String TAB_STYLE_BUTTON_COLOR = "tabBarButtonColor";
@@ -52,7 +54,9 @@ public class BottomTabActivity extends BaseReactActivity implements AHBottomNavi
52 54
         mContentFrame = (FrameLayout) findViewById(R.id.contentFrame);
53 55
 
54 56
         final ArrayList<Screen> screens = (ArrayList<Screen>) getIntent().getSerializableExtra(EXTRA_SCREENS);
57
+        final Drawer drawer = (Drawer) getIntent().getSerializableExtra(DRAWER_PARAMS);
55 58
         mBottomNavigation.setForceTint(true);
59
+        setupDrawer(screens.get(0), drawer, R.id.drawerFrame, R.id.drawerLayout);
56 60
         setupTabs(getIntent().getExtras());
57 61
         setupPages(screens);
58 62
 
@@ -190,9 +194,9 @@ public class BottomTabActivity extends BaseReactActivity implements AHBottomNavi
190 194
 
191 195
         // Hide or show back button if needed
192 196
         if (getScreenStackSize() > 1) {
193
-            mToolbar.showBackButton(getCurrentScreen());
197
+            mToolbar.setNavUpButton(getCurrentScreen());
194 198
         } else {
195
-            mToolbar.hideBackButton();
199
+            mToolbar.setNavUpButton();
196 200
         }
197 201
     }
198 202
 

+ 7
- 1
android/app/src/main/java/com/reactnativenavigation/activities/SingleScreenActivity.java View File

@@ -4,6 +4,7 @@ import android.widget.FrameLayout;
4 4
 
5 5
 import com.reactnativenavigation.R;
6 6
 import com.reactnativenavigation.core.RctManager;
7
+import com.reactnativenavigation.core.objects.Drawer;
7 8
 import com.reactnativenavigation.core.objects.Screen;
8 9
 import com.reactnativenavigation.utils.StyleHelper;
9 10
 import com.reactnativenavigation.views.RnnToolBar;
@@ -14,6 +15,7 @@ import com.reactnativenavigation.views.ScreenStack;
14 15
  */
15 16
 public class SingleScreenActivity extends BaseReactActivity {
16 17
 
18
+    public static final String DRAWER_PARAMS = "drawerParams";
17 19
     public static final String EXTRA_SCREEN = "extraScreen";
18 20
 
19 21
     private ScreenStack mScreenStack;
@@ -27,7 +29,11 @@ public class SingleScreenActivity extends BaseReactActivity {
27 29
         mToolbar = (RnnToolBar) findViewById(R.id.toolbar);
28 30
 
29 31
         final Screen screen = (Screen) getIntent().getSerializableExtra(EXTRA_SCREEN);
32
+        final Drawer drawer = (Drawer) getIntent().getSerializableExtra(DRAWER_PARAMS);
33
+
30 34
         mNavigatorId = screen.navigatorId;
35
+        setupToolbar(screen);
36
+        setupDrawer(screen, drawer, R.id.drawerFrame, R.id.drawerLayout);
31 37
 
32 38
         mScreenStack = new ScreenStack(this);
33 39
         FrameLayout contentFrame = (FrameLayout) findViewById(R.id.contentFrame);
@@ -48,7 +54,7 @@ public class SingleScreenActivity extends BaseReactActivity {
48 54
         mToolbar.update(screen);
49 55
         StyleHelper.updateStyles(mToolbar, screen);
50 56
     }
51
-    
57
+
52 58
     @Override
53 59
     public void push(Screen screen) {
54 60
         super.push(screen);

+ 23
- 0
android/app/src/main/java/com/reactnativenavigation/core/objects/Drawer.java View File

@@ -0,0 +1,23 @@
1
+package com.reactnativenavigation.core.objects;
2
+
3
+import com.facebook.react.bridge.ReadableMap;
4
+
5
+import java.io.Serializable;
6
+
7
+public class Drawer extends JsonObject implements Serializable {
8
+    private static final long serialVersionUID = 982836768712398756L;
9
+
10
+    private static final String KEY_LEFT = "left";
11
+    private static final String KEY_RIGHT = "right";
12
+    private static final String KEY_DISABLE_OPEN_GESTURE = "disableOpenGesture";
13
+
14
+    public final Screen left;
15
+    public final Screen right;
16
+    public final boolean disableOpenGesture;
17
+
18
+    public Drawer(ReadableMap params) {
19
+        left = params.hasKey(KEY_LEFT) ? new Screen(params.getMap(KEY_LEFT)) : null;
20
+        right = params.hasKey(KEY_RIGHT) ? new Screen(params.getMap(KEY_RIGHT)) : null;
21
+        disableOpenGesture = getBoolean(params, KEY_DISABLE_OPEN_GESTURE);
22
+    }
23
+}

+ 6
- 2
android/app/src/main/java/com/reactnativenavigation/core/objects/Screen.java View File

@@ -34,7 +34,7 @@ public class Screen extends JsonObject implements Serializable {
34 34
     private static final String KEY_RIGHT_BUTTONS = "rightButtons";
35 35
     private static final String KEY_TOOL_BAR_STYLE = "navigatorStyle";
36 36
     private static final String KEY_STATUS_BAR_COLOR = "statusBarColor";
37
-    private static final String KEY_TOOL_BAR_COLOR = "toolBarColor";
37
+    private static final String KEY_TOOL_BAR_COLOR = "navBarBackgroundColor";
38 38
     private static final String KEY_TOOL_BAR_HIDDEN = "navBarHidden";
39 39
     private static final String KEY_NAVIGATION_BAR_COLOR = "navigationBarColor";
40 40
     private static final String KEY_NAV_BAR_BUTTON_COLOR = "navBarButtonColor";
@@ -44,7 +44,7 @@ public class Screen extends JsonObject implements Serializable {
44 44
     private static final String KEY_TAB_INDICATOR_COLOR = "tabIndicatorColor";
45 45
     private static final String KEY_PROPS = "passProps";
46 46
 
47
-    public final String title;
47
+    public String title;
48 48
     public final String label;
49 49
     public final String screenId;
50 50
     public final String screenInstanceId;
@@ -85,6 +85,10 @@ public class Screen extends JsonObject implements Serializable {
85 85
         setToolbarStyle(screen);
86 86
     }
87 87
 
88
+    public void setTitle(ReadableMap params) {
89
+        this.title = getString(params, KEY_TITLE);
90
+    }
91
+
88 92
     public void setButtons(ReadableMap params) {
89 93
         this.buttons = getButtons(params);
90 94
     }

+ 23
- 2
android/app/src/main/java/com/reactnativenavigation/modules/RctActivityModule.java View File

@@ -15,6 +15,7 @@ import com.reactnativenavigation.activities.BottomTabActivity;
15 15
 import com.reactnativenavigation.activities.RootActivity;
16 16
 import com.reactnativenavigation.activities.SingleScreenActivity;
17 17
 import com.reactnativenavigation.controllers.ModalController;
18
+import com.reactnativenavigation.core.objects.Drawer;
18 19
 import com.reactnativenavigation.core.objects.Screen;
19 20
 import com.reactnativenavigation.modal.RnnModal;
20 21
 import com.reactnativenavigation.utils.BridgeUtils;
@@ -39,7 +40,7 @@ public class RctActivityModule extends ReactContextBaseJavaModule {
39 40
     }
40 41
 
41 42
     @ReactMethod
42
-    public void startTabBasedApp(ReadableArray screens, ReadableMap style) {
43
+    public void startTabBasedApp(ReadableArray screens, ReadableMap style, ReadableMap drawerParams) {
43 44
         Activity context = ContextProvider.getActivityContext();
44 45
         if (context != null && !context.isFinishing()) {
45 46
             Intent intent = new Intent(context, BottomTabActivity.class);
@@ -47,6 +48,9 @@ public class RctActivityModule extends ReactContextBaseJavaModule {
47 48
 
48 49
             Bundle extras = new Bundle();
49 50
             extras.putSerializable(BottomTabActivity.EXTRA_SCREENS, createScreens(screens));
51
+            if (drawerParams != null) {
52
+                extras.putSerializable(BottomTabActivity.DRAWER_PARAMS, new Drawer(drawerParams));
53
+            }
50 54
             if (style != null) {
51 55
                 BridgeUtils.addMapToBundle(((ReadableNativeMap) style).toHashMap(), extras);
52 56
             }
@@ -72,7 +76,7 @@ public class RctActivityModule extends ReactContextBaseJavaModule {
72 76
     }
73 77
 
74 78
     @ReactMethod
75
-    public void startSingleScreenApp(ReadableMap screen) {
79
+    public void startSingleScreenApp(ReadableMap screen, ReadableMap drawerParams) {
76 80
         BaseReactActivity context = ContextProvider.getActivityContext();
77 81
         if (context != null && !context.isFinishing()) {
78 82
             Intent intent = new Intent(context, SingleScreenActivity.class);
@@ -80,6 +84,9 @@ public class RctActivityModule extends ReactContextBaseJavaModule {
80 84
 
81 85
             Bundle extras = new Bundle();
82 86
             extras.putSerializable(SingleScreenActivity.EXTRA_SCREEN, new Screen(screen));
87
+            if (drawerParams != null) {
88
+                extras.putSerializable(SingleScreenActivity.DRAWER_PARAMS, new Drawer(drawerParams));
89
+            }
83 90
             intent.putExtras(extras);
84 91
 
85 92
             context.startActivity(intent);
@@ -148,6 +155,20 @@ public class RctActivityModule extends ReactContextBaseJavaModule {
148 155
         });
149 156
     }
150 157
 
158
+    @ReactMethod
159
+    public void toggleDrawer(final ReadableMap params) {
160
+        final BaseReactActivity context = ContextProvider.getActivityContext();
161
+        if (context == null || context.isFinishing()) {
162
+            return;
163
+        }
164
+        context.runOnUiThread(new Runnable() {
165
+            @Override
166
+            public void run() {
167
+                context.toggleDrawer(params);
168
+            }
169
+        });
170
+    }
171
+
151 172
     @ReactMethod
152 173
     public void toggleNavigationBar(final ReadableMap params) {
153 174
         final BaseReactActivity context = ContextProvider.getActivityContext();

+ 139
- 19
android/app/src/main/java/com/reactnativenavigation/views/RnnToolBar.java View File

@@ -12,10 +12,14 @@ import android.support.annotation.NonNull;
12 12
 import android.support.annotation.UiThread;
13 13
 import android.support.v4.content.ContextCompat;
14 14
 import android.support.v4.content.res.ResourcesCompat;
15
+import android.support.v4.widget.DrawerLayout;
15 16
 import android.support.v7.app.ActionBar;
17
+import android.support.v7.app.ActionBarDrawerToggle;
16 18
 import android.support.v7.app.AppCompatActivity;
19
+import android.support.v7.graphics.drawable.DrawerArrowDrawable;
17 20
 import android.support.v7.widget.Toolbar;
18 21
 import android.util.AttributeSet;
22
+import android.view.Gravity;
19 23
 import android.view.Menu;
20 24
 import android.view.MenuItem;
21 25
 import android.view.View;
@@ -27,6 +31,7 @@ import com.reactnativenavigation.activities.BaseReactActivity;
27 31
 import com.reactnativenavigation.core.objects.Button;
28 32
 import com.reactnativenavigation.core.objects.Screen;
29 33
 import com.reactnativenavigation.utils.ContextProvider;
34
+import com.reactnativenavigation.utils.IconUtils;
30 35
 import com.reactnativenavigation.utils.ImageUtils;
31 36
 
32 37
 import java.lang.ref.WeakReference;
@@ -43,8 +48,13 @@ public class RnnToolBar extends Toolbar {
43 48
     private static final int ANIMATE_DURATION = 180;
44 49
 
45 50
     private List<Screen> mScreens;
51
+    private AsyncTask mDrawerIconTask;
46 52
     private AsyncTask mSetupToolbarTask;
47 53
     private Drawable mBackground;
54
+    private Drawable mDrawerIcon;
55
+    private Screen mDrawerScreen;
56
+    private DrawerLayout mDrawerLayout;
57
+    private ActionBarDrawerToggle mDrawerToggle;
48 58
     private ArrayList<View> mMenuItems;
49 59
 
50 60
     public RnnToolBar(Context context) {
@@ -105,6 +115,65 @@ public class RnnToolBar extends Toolbar {
105 115
         }
106 116
     }
107 117
 
118
+    public ActionBarDrawerToggle setupDrawer(DrawerLayout drawerLayout, Screen drawerScreen, Screen screen) {
119
+        if (drawerLayout == null || drawerScreen == null) {
120
+            return null;
121
+        }
122
+
123
+        mDrawerLayout = drawerLayout;
124
+        mDrawerScreen = drawerScreen;
125
+        mDrawerToggle = new ActionBarDrawerToggle(
126
+            ContextProvider.getActivityContext(),
127
+            mDrawerLayout,
128
+            this,
129
+            R.string.drawer_open,
130
+            R.string.drawer_close
131
+        );
132
+        mDrawerLayout.setDrawerListener(mDrawerToggle);
133
+        setupDrawerIconAsync(drawerScreen.icon, screen);
134
+
135
+        return mDrawerToggle;
136
+    }
137
+
138
+    public void setDrawerIcon(Drawable icon) {
139
+        mDrawerIcon = icon;
140
+    }
141
+
142
+    public void showDrawer(boolean animated) {
143
+        if (mDrawerLayout == null) {
144
+            return;
145
+        }
146
+
147
+        mDrawerLayout.openDrawer(Gravity.LEFT);
148
+    }
149
+
150
+    public void hideDrawer(boolean animated) {
151
+        if (mDrawerLayout == null) {
152
+            return;
153
+        }
154
+
155
+        mDrawerLayout.closeDrawer(Gravity.LEFT);
156
+    }
157
+
158
+    public void toggleDrawer(boolean animated) {
159
+        if (mDrawerLayout == null) {
160
+            return;
161
+        }
162
+
163
+        boolean visible = mDrawerLayout.isDrawerOpen(Gravity.LEFT);
164
+        if (visible) {
165
+            hideDrawer(animated);
166
+        } else {
167
+            showDrawer(animated);
168
+        }
169
+    }
170
+
171
+    public void setupDrawerIconAsync(String drawerIconSource, Screen screen) {
172
+        if (mDrawerIconTask == null) {
173
+            mDrawerIconTask = new SetupDrawerIconTask(this, drawerIconSource, screen).execute();
174
+        }
175
+    }
176
+
108 177
     public void setupToolbarButtonsAsync(Screen newScreen) {
109 178
         if (newScreen != null) {
110 179
             this.setupToolbarButtonsAsync(null, newScreen);
@@ -144,29 +213,44 @@ public class RnnToolBar extends Toolbar {
144 213
         hideToolbar(false);
145 214
     }
146 215
 
147
-    @SuppressWarnings({"ConstantConditions"})
148
-    public void showBackButton(Screen screen) {
149
-        ActionBar actionBar = ContextProvider.getActivityContext().getSupportActionBar();
150
-        Drawable backButton = setupBackButton(screen);
151
-        actionBar.setHomeAsUpIndicator(backButton);
152
-        actionBar.setDisplayHomeAsUpEnabled(true);
216
+    public void setNavUpButton() {
217
+        setNavUpButton(null);
153 218
     }
154 219
 
155
-    @SuppressLint("PrivateResource")
156 220
     @SuppressWarnings({"ConstantConditions"})
157
-    private Drawable setupBackButton(Screen screen) {
158
-        Resources resources = getResources();
159
-        final Drawable backButton = ResourcesCompat.getDrawable(resources,
160
-                R.drawable.abc_ic_ab_back_mtrl_am_alpha,
161
-                ContextProvider.getActivityContext().getTheme());
162
-        int tintColor = screen.navBarButtonColor != null ? screen.navBarButtonColor : Color.BLACK;
163
-        ImageUtils.tint(backButton, tintColor);
164
-        return backButton;
165
-    }
221
+    public void setNavUpButton(Screen screen) {
222
+        ActionBar actionBar = ContextProvider.getActivityContext().getSupportActionBar();
223
+        if (actionBar == null) {
224
+            return;
225
+        }
166 226
 
167
-    @SuppressWarnings({"ConstantConditions"})
168
-    public void hideBackButton() {
169
-        ContextProvider.getActivityContext().getSupportActionBar().setDisplayHomeAsUpEnabled(false);
227
+        boolean isBack = screen != null;
228
+        boolean hasDrawer = mDrawerToggle != null;
229
+
230
+        Drawable navIcon = null;
231
+        DrawerArrowDrawable navArrow = null;
232
+        if (hasDrawer && mDrawerIcon == null) {
233
+            navArrow = (DrawerArrowDrawable) this.getNavigationIcon();
234
+        } else {
235
+            if (isBack) {
236
+                navArrow = new DrawerArrowDrawable(ContextProvider.getActivityContext());
237
+            } else if (hasDrawer) {
238
+                navIcon = mDrawerIcon;
239
+            }
240
+        }
241
+
242
+        if (navArrow != null) {
243
+            navArrow.setProgress(isBack ? 1.0f : 0.0f);
244
+            if (screen != null && screen.navBarButtonColor != null) {
245
+                navArrow.setColor(screen.navBarButtonColor);
246
+            } else {
247
+                navArrow.setColor(Color.BLACK);
248
+            }
249
+            navIcon = navArrow;
250
+        }
251
+
252
+        actionBar.setHomeAsUpIndicator(navIcon);
253
+        actionBar.setDisplayHomeAsUpEnabled(navIcon != null);
170 254
     }
171 255
 
172 256
     /**
@@ -186,6 +270,42 @@ public class RnnToolBar extends Toolbar {
186 270
         setupToolbarButtonsAsync(screen);
187 271
     }
188 272
 
273
+    private static class SetupDrawerIconTask extends AsyncTask<Void, Void, Drawable> {
274
+        private final WeakReference<RnnToolBar> mToolbarWR;
275
+        private final String mDrawerIconSource;
276
+        private final Integer mTintColor;
277
+
278
+        public SetupDrawerIconTask(RnnToolBar toolBar, String drawerIconSource, Screen screen) {
279
+            mToolbarWR = new WeakReference<>(toolBar);
280
+            mDrawerIconSource = drawerIconSource;
281
+            mTintColor = screen.navBarButtonColor;
282
+        }
283
+
284
+        @Override
285
+        protected Drawable doInBackground(Void... params) {
286
+            Context context = ContextProvider.getActivityContext();
287
+            if (context == null || mDrawerIconSource == null) {
288
+                return null;
289
+            }
290
+
291
+            return IconUtils.getIcon(context, mDrawerIconSource);
292
+        }
293
+
294
+        @Override
295
+        protected void onPostExecute(Drawable drawerIcon) {
296
+            RnnToolBar toolBar = mToolbarWR.get();
297
+            if (drawerIcon != null) {
298
+                if (mTintColor != null) {
299
+                    ImageUtils.tint(drawerIcon, mTintColor);
300
+                }
301
+                toolBar.setDrawerIcon(drawerIcon);
302
+            }
303
+
304
+            toolBar.setNavUpButton();
305
+            mToolbarWR.clear();
306
+        }
307
+    }
308
+
189 309
     private static class SetupToolbarButtonsTask extends AsyncTask<Void, Void, Map<String, Drawable>> {
190 310
         private final List<Button> mOldButtons;
191 311
         private final List<Button> mNewButtons;

+ 14
- 3
android/app/src/main/res/layout/bottom_tab_activity.xml View File

@@ -20,11 +20,22 @@
20 20
             app:layout_scrollFlags="scroll|enterAlways"/>
21 21
     </android.support.design.widget.AppBarLayout>
22 22
 
23
-    <FrameLayout
24
-        android:id="@+id/contentFrame"
23
+    <android.support.v4.widget.DrawerLayout
24
+        xmlns:android="http://schemas.android.com/apk/res/android"
25
+        android:id="@+id/drawerLayout"
25 26
         android:layout_width="match_parent"
26 27
         android:layout_height="0dp"
27
-        android:layout_weight="1"/>
28
+        android:layout_weight="1">
29
+        <FrameLayout
30
+            android:id="@+id/contentFrame"
31
+            android:layout_width="match_parent"
32
+            android:layout_height="0dp"
33
+            android:layout_weight="1"/>
34
+        <FrameLayout android:id="@+id/drawerFrame"
35
+            android:layout_width="240dp"
36
+            android:layout_height="match_parent"
37
+            android:layout_gravity="start"/>
38
+    </android.support.v4.widget.DrawerLayout>
28 39
 
29 40
     <com.aurelhubert.ahbottomnavigation.AHBottomNavigation
30 41
         android:id="@+id/bottom_tab_bar"

+ 13
- 3
android/app/src/main/res/layout/single_screen_activity.xml View File

@@ -17,8 +17,18 @@
17 17
             app:layout_scrollFlags="scroll|enterAlways"/>
18 18
     </android.support.design.widget.AppBarLayout>
19 19
 
20
-    <FrameLayout
21
-        android:id="@+id/contentFrame"
20
+    <android.support.v4.widget.DrawerLayout
21
+        xmlns:android="http://schemas.android.com/apk/res/android"
22
+        android:id="@+id/drawerLayout"
22 23
         android:layout_width="match_parent"
23
-        android:layout_height="match_parent"/>
24
+        android:layout_height="match_parent">
25
+        <FrameLayout
26
+            android:id="@+id/contentFrame"
27
+            android:layout_width="match_parent"
28
+            android:layout_height="match_parent"/>
29
+        <FrameLayout android:id="@+id/drawerFrame"
30
+            android:layout_width="240dp"
31
+            android:layout_height="match_parent"
32
+            android:layout_gravity="start"/>
33
+    </android.support.v4.widget.DrawerLayout>
24 34
 </LinearLayout>

+ 5
- 0
android/app/src/main/res/values/strings.xml View File

@@ -0,0 +1,5 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<resources>
3
+    <string name="drawer_close">Drawer Close</string>
4
+    <string name="drawer_open">Drawer Open</string>
5
+</resources>

+ 31
- 2
src/platformSpecific.android.js View File

@@ -19,7 +19,8 @@ function startSingleScreenApp(params) {
19 19
   addNavigatorButtons(screen);
20 20
   addNavigationStyleParams(screen);
21 21
   screen.passProps = params.passProps;
22
-  RctActivity.startSingleScreenApp(screen);
22
+  const drawer = setupDrawer(params.drawer);
23
+  RctActivity.startSingleScreenApp(screen, drawer);
23 24
 }
24 25
 
25 26
 function startTabBasedApp(params) {
@@ -41,7 +42,8 @@ function startTabBasedApp(params) {
41 42
     tab.passProps = params.passProps;
42 43
   });
43 44
 
44
-  RctActivity.startTabBasedApp(params.tabs, params.tabsStyle);
45
+  const drawer = setupDrawer(params.drawer);
46
+  RctActivity.startTabBasedApp(params.tabs, params.tabsStyle, drawer);
45 47
 }
46 48
 
47 49
 function navigatorPush(navigator, params) {
@@ -101,6 +103,14 @@ function navigatorSwitchToTab(navigator, params) {
101 103
   });
102 104
 }
103 105
 
106
+function navigatorToggleDrawer(navigator, params) {
107
+  RctActivity.toggleDrawer({
108
+    side: params.side,
109
+    animated: !(params.animated === false),
110
+    to: params.to || ''
111
+  });
112
+}
113
+
104 114
 function navigatorToggleNavBar(navigator, params) {
105 115
   RctActivity.toggleNavigationBar({
106 116
     hidden: params.to === 'hidden',
@@ -160,6 +170,24 @@ function addNavigationStyleParams(screen) {
160 170
   screen.navigatorStyle = Object.assign({}, screen.navigatorStyle, Screen.navigatorStyle);
161 171
 }
162 172
 
173
+function setupDrawer(drawerParams) {
174
+  const drawer = Object.assign({}, drawerParams);
175
+  [drawer.left, drawer.right].forEach(side => {
176
+    if (!side) {
177
+      return;
178
+    }
179
+    const icon = resolveAssetSource(side.icon);
180
+    if (icon) {
181
+      side.icon = icon.uri;
182
+    }
183
+  });
184
+  if (drawer.disableOpenGesture === undefined) {
185
+    drawer.disableOpenGesture = false;
186
+  };
187
+
188
+  return drawer;
189
+}
190
+
163 191
 export default {
164 192
   startTabBasedApp,
165 193
   startSingleScreenApp,
@@ -174,6 +202,7 @@ export default {
174 202
   navigatorSetTabBadge,
175 203
   navigatorSetTitle,
176 204
   navigatorSwitchToTab,
205
+  navigatorToggleDrawer,
177 206
   navigatorToggleTabs,
178 207
   navigatorToggleNavBar
179 208
 }