Browse Source

Top bar options changes (#2771)

* Rename TopBar.animateHide to animate

also fix some options in playground app

* Consolidate topBar visibility in childWillDisappear

* Rename BottomTabs.animateHide to animate
Guy Carmeli 6 years ago
parent
commit
e4ed6ca32f
No account linked to committer's email address
18 changed files with 155 additions and 100 deletions
  1. 3
    5
      lib/android/app/src/main/java/com/reactnativenavigation/anim/NavigationAnimator.java
  2. 16
    15
      lib/android/app/src/main/java/com/reactnativenavigation/anim/TopBarAnimator.java
  3. 7
    7
      lib/android/app/src/main/java/com/reactnativenavigation/parse/BottomTabsOptions.java
  4. 6
    6
      lib/android/app/src/main/java/com/reactnativenavigation/parse/TopBarOptions.java
  5. 12
    7
      lib/android/app/src/main/java/com/reactnativenavigation/presentation/OptionsPresenter.java
  6. 22
    24
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/StackController.java
  7. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ViewController.java
  8. 1
    1
      lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabsController.java
  9. 13
    10
      lib/android/app/src/main/java/com/reactnativenavigation/views/StackLayout.java
  10. 2
    2
      lib/android/app/src/main/java/com/reactnativenavigation/views/TopBar.java
  11. 7
    7
      lib/android/app/src/test/java/com/reactnativenavigation/parse/OptionsTest.java
  12. 1
    1
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/OptionsApplyingTest.java
  13. 47
    0
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/StackControllerTest.java
  14. 9
    3
      lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TopTabsViewControllerTest.java
  15. 1
    7
      playground/src/app.js
  16. 2
    2
      playground/src/screens/OptionsScreen.js
  17. 1
    1
      playground/src/screens/TextScreen.js
  18. 4
    1
      playground/src/screens/WelcomeScreen.js

+ 3
- 5
lib/android/app/src/main/java/com/reactnativenavigation/anim/NavigationAnimator.java View File

@@ -57,7 +57,7 @@ public class NavigationAnimator {
57 57
 
58 58
     public void animatePop(View view, @Nullable final NavigationAnimationListener animationListener) {
59 59
         ObjectAnimator alpha = ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0);
60
-        alpha.setInterpolator(ACCELERATE_INTERPOLATOR);
60
+        ObjectAnimator translationY = ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, 0, this.translationY);
61 61
 
62 62
         AnimatorSet set = new AnimatorSet();
63 63
         set.addListener(new AnimatorListenerAdapter() {
@@ -68,11 +68,9 @@ public class NavigationAnimator {
68 68
                 }
69 69
             }
70 70
         });
71
-        ObjectAnimator translationY = ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, 0, this.translationY);
72
-        translationY.setInterpolator(ACCELERATE_INTERPOLATOR);
73
-        translationY.setDuration(DURATION);
74
-        alpha.setDuration(DURATION);
75 71
         set.playTogether(translationY, alpha);
72
+        set.setDuration(DURATION);
73
+        set.setInterpolator(ACCELERATE_INTERPOLATOR);
76 74
         set.start();
77 75
     }
78 76
 }

+ 16
- 15
lib/android/app/src/main/java/com/reactnativenavigation/anim/TopBarAnimator.java View File

@@ -20,26 +20,23 @@ public class TopBarAnimator {
20 20
 
21 21
     private TopBar topBar;
22 22
     private View contentView;
23
+    private ObjectAnimator hideAnimator;
24
+    private ObjectAnimator showAnimator;
23 25
 
24 26
     public TopBarAnimator(TopBar topBar) {
25 27
         this.topBar = topBar;
26 28
     }
27 29
 
28
-    public TopBarAnimator(TopBar topBar, View contentView) {
29
-        this.topBar = topBar;
30
-        this.contentView = contentView;
31
-    }
32
-
33 30
     public void show() {
34 31
         show(-1 * topBar.getMeasuredHeight(), decelerateInterpolator, DURATION_TOPBAR);
35 32
     }
36 33
 
37 34
     public void show(float startTranslation, TimeInterpolator interpolator, int duration) {
38
-        ObjectAnimator topbarAnim = ObjectAnimator.ofFloat(topBar, View.TRANSLATION_Y, startTranslation, 0);
39
-        topbarAnim.setInterpolator(interpolator);
40
-        topbarAnim.setDuration(duration);
35
+        showAnimator = ObjectAnimator.ofFloat(topBar, View.TRANSLATION_Y, startTranslation, 0);
36
+        showAnimator.setInterpolator(interpolator);
37
+        showAnimator.setDuration(duration);
41 38
 
42
-        topbarAnim.addListener(new AnimatorListenerAdapter() {
39
+        showAnimator.addListener(new AnimatorListenerAdapter() {
43 40
 
44 41
             @Override
45 42
             public void onAnimationStart(Animator animation) {
@@ -55,7 +52,7 @@ public class TopBarAnimator {
55 52
                 }
56 53
             }
57 54
         });
58
-        topbarAnim.start();
55
+        showAnimator.start();
59 56
     }
60 57
 
61 58
     public void hide() {
@@ -63,11 +60,11 @@ public class TopBarAnimator {
63 60
     }
64 61
 
65 62
     void hide(float startTranslation, TimeInterpolator interpolator, int duration) {
66
-        ObjectAnimator animator = ObjectAnimator.ofFloat(topBar, View.TRANSLATION_Y, startTranslation, -1 * topBar.getMeasuredHeight());
67
-        animator.setInterpolator(interpolator);
68
-        animator.setDuration(duration);
63
+        hideAnimator = ObjectAnimator.ofFloat(topBar, View.TRANSLATION_Y, startTranslation, -1 * topBar.getMeasuredHeight());
64
+        hideAnimator.setInterpolator(interpolator);
65
+        hideAnimator.setDuration(duration);
69 66
 
70
-        animator.addListener(new AnimatorListenerAdapter() {
67
+        hideAnimator.addListener(new AnimatorListenerAdapter() {
71 68
             @Override
72 69
             public void onAnimationEnd(Animator animation) {
73 70
                 if (contentView != null) {
@@ -79,6 +76,10 @@ public class TopBarAnimator {
79 76
                 topBar.setVisibility(View.GONE);
80 77
             }
81 78
         });
82
-        animator.start();
79
+        hideAnimator.start();
80
+    }
81
+
82
+    public boolean isRunning() {
83
+        return (hideAnimator != null && hideAnimator.isRunning()) || (showAnimator != null && showAnimator.isRunning());
83 84
     }
84 85
 }

+ 7
- 7
lib/android/app/src/main/java/com/reactnativenavigation/parse/BottomTabsOptions.java View File

@@ -18,7 +18,7 @@ public class BottomTabsOptions implements DEFAULT_VALUES {
18 18
         options.currentTabId = TextParser.parse(json, "currentTabId");
19 19
 		options.currentTabIndex = NumberParser.parse(json,"currentTabIndex");
20 20
 		options.visible = BoolParser.parse(json,"visible");
21
-		options.animateHide = BoolParser.parse(json,"animateHide");
21
+		options.animate = BoolParser.parse(json,"animate");
22 22
         options.testId = TextParser.parse(json, "testID");
23 23
 
24 24
 		return options;
@@ -27,8 +27,8 @@ public class BottomTabsOptions implements DEFAULT_VALUES {
27 27
     public Color backgroundColor = new NullColor();
28 28
     public Color tabColor = new NullColor();
29 29
     public Color selectedTabColor = new NullColor();
30
-	Bool visible = new NullBool();
31
-	Bool animateHide = new NullBool();
30
+	public Bool visible = new NullBool();
31
+	public Bool animate = new NullBool();
32 32
 	public Number currentTabIndex = new NullNumber();
33 33
 	public Text currentTabId = new NullText();
34 34
     public Text testId = new NullText();
@@ -43,8 +43,8 @@ public class BottomTabsOptions implements DEFAULT_VALUES {
43 43
 		if (other.visible.hasValue()) {
44 44
 			visible = other.visible;
45 45
 		}
46
-		if (other.animateHide.hasValue()) {
47
-			animateHide = other.animateHide;
46
+		if (other.animate.hasValue()) {
47
+			animate = other.animate;
48 48
 		}
49 49
         if (other.tabColor.hasValue()) {
50 50
             tabColor = other.tabColor;
@@ -67,8 +67,8 @@ public class BottomTabsOptions implements DEFAULT_VALUES {
67 67
         if (!visible.hasValue()) {
68 68
             visible = defaultOptions.visible;
69 69
         }
70
-        if (!animateHide.hasValue()) {
71
-            animateHide = defaultOptions.animateHide;
70
+        if (!animate.hasValue()) {
71
+            animate = defaultOptions.animate;
72 72
         }
73 73
         if (!tabColor.hasValue()) {
74 74
             tabColor = defaultOptions.tabColor;

+ 6
- 6
lib/android/app/src/main/java/com/reactnativenavigation/parse/TopBarOptions.java View File

@@ -25,7 +25,7 @@ public class TopBarOptions implements DEFAULT_VALUES {
25 25
         options.textFontSize = FractionParser.parse(json, "textFontSize");
26 26
         options.textFontFamily = typefaceManager.getTypeFace(json.optString("textFontFamily", ""));
27 27
         options.visible = BoolParser.parse(json, "visible");
28
-        options.animateHide = BoolParser.parse(json,"animateHide");
28
+        options.animate = BoolParser.parse(json,"animate");
29 29
         options.hideOnScroll = BoolParser.parse(json,"hideOnScroll");
30 30
         options.drawBehind = BoolParser.parse(json,"drawBehind");
31 31
         options.rightButtons = Button.parseJsonArray(json.optJSONArray("rightButtons"));
@@ -42,7 +42,7 @@ public class TopBarOptions implements DEFAULT_VALUES {
42 42
     public Fraction textFontSize = new NullFraction();
43 43
     @Nullable public Typeface textFontFamily;
44 44
     public Bool visible = new NullBool();
45
-    public Bool animateHide = new NullBool();
45
+    public Bool animate = new NullBool();
46 46
     public Bool hideOnScroll = new NullBool();
47 47
     public Bool drawBehind = new NullBool();
48 48
     public ArrayList<Button> leftButtons;
@@ -62,8 +62,8 @@ public class TopBarOptions implements DEFAULT_VALUES {
62 62
         if (other.visible.hasValue()) {
63 63
             visible = other.visible;
64 64
         }
65
-        if (other.animateHide.hasValue()) {
66
-            animateHide = other.animateHide;
65
+        if (other.animate.hasValue()) {
66
+            animate = other.animate;
67 67
         }
68 68
         if (other.hideOnScroll.hasValue()) {
69 69
             hideOnScroll = other.hideOnScroll;
@@ -90,8 +90,8 @@ public class TopBarOptions implements DEFAULT_VALUES {
90 90
             textFontFamily = defaultOptions.textFontFamily;
91 91
         if (!visible.hasValue())
92 92
             visible = defaultOptions.visible;
93
-        if (!animateHide.hasValue())
94
-            animateHide = defaultOptions.animateHide;
93
+        if (!animate.hasValue())
94
+            animate = defaultOptions.animate;
95 95
         if (!hideOnScroll.hasValue())
96 96
             hideOnScroll = defaultOptions.hideOnScroll;
97 97
         if (!drawBehind.hasValue())

+ 12
- 7
lib/android/app/src/main/java/com/reactnativenavigation/presentation/OptionsPresenter.java View File

@@ -1,15 +1,10 @@
1 1
 package com.reactnativenavigation.presentation;
2 2
 
3
-import android.view.View;
4
-
5
-import com.github.clans.fab.FloatingActionButton;
6 3
 import com.reactnativenavigation.parse.Button;
7
-import com.reactnativenavigation.parse.FabOptions;
8 4
 import com.reactnativenavigation.parse.Options;
9 5
 import com.reactnativenavigation.parse.TopBarOptions;
10 6
 import com.reactnativenavigation.parse.TopTabOptions;
11 7
 import com.reactnativenavigation.parse.TopTabsOptions;
12
-import com.reactnativenavigation.views.Fab;
13 8
 import com.reactnativenavigation.views.ReactComponent;
14 9
 import com.reactnativenavigation.views.TopBar;
15 10
 
@@ -24,6 +19,10 @@ public class OptionsPresenter {
24 19
         this.component = component;
25 20
     }
26 21
 
22
+    public OptionsPresenter(TopBar topBar) {
23
+        this.topBar = topBar;
24
+    }
25
+
27 26
     public void applyOptions(Options options) {
28 27
         applyButtons(options.topBarOptions.leftButtons, options.topBarOptions.rightButtons);
29 28
         applyTopBarOptions(options.topBarOptions);
@@ -40,10 +39,10 @@ public class OptionsPresenter {
40 39
 
41 40
         topBar.setTitleTypeface(options.textFontFamily);
42 41
         if (options.visible.isFalse()) {
43
-            topBar.hide(options.animateHide);
42
+            topBar.hide(options.animate);
44 43
         }
45 44
         if (options.visible.isTrueOrUndefined()) {
46
-            topBar.show(options.animateHide);
45
+            topBar.show(options.animate);
47 46
         }
48 47
         if (options.drawBehind.isTrue()) {
49 48
             component.drawBehindTopBar();
@@ -73,4 +72,10 @@ public class OptionsPresenter {
73 72
             topBar.setTopTabFontFamily(topTabOptions.tabIndex, topTabOptions.fontFamily);
74 73
         }
75 74
     }
75
+
76
+    public void onChildWillDisappear(Options disappearing, Options appearing) {
77
+        if (disappearing.topBarOptions.visible.isTrueOrUndefined() && appearing.topBarOptions.visible.isFalse()) {
78
+            topBar.hide(disappearing.topBarOptions.animate);
79
+        }
80
+    }
76 81
 }

+ 22
- 24
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/StackController.java View File

@@ -24,7 +24,6 @@ public class StackController extends ParentController <StackLayout> {
24 24
     private static final NoOpPromise NO_OP = new NoOpPromise();
25 25
     private final IdStack<ViewController> stack = new IdStack<>();
26 26
     private final NavigationAnimator animator;
27
-    private StackLayout stackLayout;
28 27
 
29 28
     public StackController(final Activity activity, String id, Options initialOptions) {
30 29
         super(activity, id, initialOptions);
@@ -33,26 +32,26 @@ public class StackController extends ParentController <StackLayout> {
33 32
 
34 33
     @RestrictTo(RestrictTo.Scope.TESTS)
35 34
     TopBar getTopBar() {
36
-        return stackLayout.getTopBar();
35
+        return getView().getTopBar();
37 36
     }
38 37
 
39 38
     @RestrictTo(RestrictTo.Scope.TESTS)
40
-    StackLayout getStackLayout() {return stackLayout;}
39
+    StackLayout getStackLayout() {return getView();}
41 40
 
42 41
     @Override
43 42
     public void applyOptions(Options options, ReactComponent component) {
44 43
         super.applyOptions(options, component);
45
-        stackLayout.applyOptions(this.options, component);
44
+        getView().applyOptions(this.options, component);
46 45
         applyOnParentController(parentController ->
47 46
                 ((ParentController) parentController).applyOptions(this.options.copy().clearTopBarOptions(), component)
48 47
         );
49
-        fabOptionsPresenter.applyOptions(options.fabOptions, component, stackLayout);
48
+        fabOptionsPresenter.applyOptions(options.fabOptions, component, getView());
50 49
     }
51 50
 
52 51
     @Override
53 52
     void clearOptions() {
54 53
         super.clearOptions();
55
-        stackLayout.clearOptions();
54
+        getView().clearOptions();
56 55
     }
57 56
 
58 57
     public void push(ViewController child, final Promise promise) {
@@ -93,31 +92,31 @@ public class StackController extends ParentController <StackLayout> {
93 92
             return;
94 93
         }
95 94
 
96
-        final ViewController poppedTop = stack.pop();
97
-        final ViewController newTop = stack.peek();
98
-        popInternal(poppedTop, newTop);
95
+        final ViewController exitingController = stack.pop();
96
+        final ViewController enteringController = stack.peek();
97
+        popInternal(exitingController, enteringController);
99 98
 
100
-        finishPopping(poppedTop.getView(), poppedTop, promise);
99
+        finishPopping(exitingController.getView(), exitingController, promise);
101 100
     }
102 101
 
103
-	private void animatePop(final Promise promise) {
102
+	void animatePop(final Promise promise) {
104 103
 		if (!canPop()) {
105 104
 			Navigator.rejectPromise(promise);
106 105
 			return;
107 106
 		}
108 107
 
109
-		final ViewController poppedTop = stack.pop();
110
-        final ViewController newTop = stack.peek();
111
-        popInternal(poppedTop, newTop);
108
+		final ViewController exitingController = stack.pop();
109
+        final ViewController enteringController = stack.peek();
110
+        popInternal(exitingController, enteringController);
112 111
 
113
-        animator.animatePop(poppedTop.getView(), () -> finishPopping(poppedTop.getView(), poppedTop, promise));
112
+        animator.animatePop(exitingController.getView(), () -> finishPopping(exitingController.getView(), exitingController, promise));
114 113
 	}
115 114
 
116
-    private void popInternal(ViewController poppedTop, ViewController newTop) {
117
-        poppedTop.onViewWillDisappear();
118
-        newTop.onViewWillAppear();
119
-        View enteringView = newTop.getView();
120
-        getView().addView(enteringView, getView().getChildCount() - 1);
115
+    private void popInternal(ViewController disappearing, ViewController appearing) {
116
+        disappearing.onViewWillDisappear();
117
+        appearing.onViewWillAppear();
118
+        getView().onChildWillDisappear(disappearing.options, appearing.options);
119
+        getView().addView(appearing.getView(), getView().indexOfChild(disappearing.getView()));
121 120
     }
122 121
 
123 122
     boolean canPop() {
@@ -200,8 +199,7 @@ public class StackController extends ParentController <StackLayout> {
200 199
     @NonNull
201 200
     @Override
202 201
     protected StackLayout createView() {
203
-        stackLayout = new StackLayout(getActivity(), this::sendOnNavigationButtonPressed);
204
-        return stackLayout;
202
+        return new StackLayout(getActivity(), this::sendOnNavigationButtonPressed);
205 203
     }
206 204
 
207 205
 	@NonNull
@@ -212,11 +210,11 @@ public class StackController extends ParentController <StackLayout> {
212 210
 
213 211
     @Override
214 212
     public void setupTopTabsWithViewPager(ViewPager viewPager) {
215
-        stackLayout.initTopTabs(viewPager);
213
+        getView().initTopTabs(viewPager);
216 214
     }
217 215
 
218 216
     @Override
219 217
     public void clearTopTabs() {
220
-        stackLayout.clearTopTabs();
218
+        getView().clearTopTabs();
221 219
     }
222 220
 }

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ViewController.java View File

@@ -41,7 +41,7 @@ public abstract class ViewController<T extends ViewGroup> implements ViewTreeObs
41 41
     private boolean isShown;
42 42
     private boolean isDestroyed;
43 43
     private ViewVisibilityListener viewVisibilityListener = new ViewVisibilityListenerAdapter();
44
-    protected FabOptionsPresenter fabOptionsPresenter;
44
+    FabOptionsPresenter fabOptionsPresenter;
45 45
 
46 46
     public ViewController(Activity activity, String id, Options initialOptions) {
47 47
         this.activity = activity;

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabsController.java View File

@@ -60,12 +60,12 @@ public class TopTabsController extends ParentController<TopTabsViewPager> implem
60 60
     @Override
61 61
     public void onViewWillDisappear() {
62 62
         super.onViewWillDisappear();
63
-        applyOnParentController(parentController -> ((ParentController) parentController).clearTopTabs());
64 63
     }
65 64
 
66 65
     @Override
67 66
     public void onViewDisappear() {
68 67
         performOnCurrentTab(ViewController::onViewDisappear);
68
+        applyOnParentController(parentController -> ((ParentController) parentController).clearTopTabs());
69 69
     }
70 70
 
71 71
     @Override

+ 13
- 10
lib/android/app/src/main/java/com/reactnativenavigation/views/StackLayout.java View File

@@ -4,14 +4,9 @@ import android.annotation.SuppressLint;
4 4
 import android.content.Context;
5 5
 import android.support.annotation.RestrictTo;
6 6
 import android.support.v4.view.ViewPager;
7
-import android.util.Log;
8
-import android.view.Gravity;
9
-import android.view.View;
10 7
 import android.widget.RelativeLayout;
11 8
 
12
-import com.github.clans.fab.FloatingActionButton;
13 9
 import com.reactnativenavigation.parse.Options;
14
-import com.reactnativenavigation.presentation.FabOptionsPresenter;
15 10
 import com.reactnativenavigation.presentation.OptionsPresenter;
16 11
 import com.reactnativenavigation.utils.CompatUtils;
17 12
 
@@ -20,8 +15,7 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
20 15
 
21 16
 @SuppressLint("ViewConstructor")
22 17
 public class StackLayout extends RelativeLayout {
23
-
24
-    private final TopBar topBar;
18
+    private TopBar topBar;
25 19
 
26 20
     public StackLayout(Context context, TitleBarButton.OnClickListener topBarButtonClickListener) {
27 21
         super(context);
@@ -39,9 +33,8 @@ public class StackLayout extends RelativeLayout {
39 33
         new OptionsPresenter(topBar, component).applyOptions(options);
40 34
     }
41 35
 
42
-    @RestrictTo(RestrictTo.Scope.TESTS)
43
-    public TopBar getTopBar() {
44
-        return topBar;
36
+    public void onChildWillDisappear(Options disappearing, Options appearing) {
37
+        new OptionsPresenter(topBar).onChildWillDisappear(disappearing, appearing);
45 38
     }
46 39
 
47 40
     public void clearOptions() {
@@ -55,4 +48,14 @@ public class StackLayout extends RelativeLayout {
55 48
     public void clearTopTabs() {
56 49
         topBar.clearTopTabs();
57 50
     }
51
+
52
+    @RestrictTo(RestrictTo.Scope.TESTS)
53
+    public TopBar getTopBar() {
54
+        return topBar;
55
+    }
56
+
57
+    @RestrictTo(RestrictTo.Scope.TESTS)
58
+    public void setTopBar(TopBar topBar) {
59
+        this.topBar = topBar;
60
+    }
58 61
 }

+ 2
- 2
lib/android/app/src/main/java/com/reactnativenavigation/views/TopBar.java View File

@@ -181,7 +181,7 @@ public class TopBar extends AppBarLayout implements ScrollEventListener.ScrollAw
181 181
         }
182 182
         if (animated.isTrueOrUndefined()) {
183 183
             animator.show();
184
-        } else {
184
+        } else if (!animator.isRunning()) {
185 185
             setVisibility(View.VISIBLE);
186 186
         }
187 187
     }
@@ -192,7 +192,7 @@ public class TopBar extends AppBarLayout implements ScrollEventListener.ScrollAw
192 192
         }
193 193
         if (animated.isTrueOrUndefined()) {
194 194
             animator.hide();
195
-        } else {
195
+        } else if (!animator.isRunning()){
196 196
             setVisibility(View.GONE);
197 197
         }
198 198
     }

+ 7
- 7
lib/android/app/src/test/java/com/reactnativenavigation/parse/OptionsTest.java View File

@@ -33,7 +33,7 @@ public class OptionsTest extends BaseTest {
33 33
     private static final Bool TOP_BAR_VISIBLE = new Bool(true);
34 34
     private static final Bool TOP_BAR_DRAW_BEHIND = new Bool(true);
35 35
     private static final Bool TOP_BAR_HIDE_ON_SCROLL = new Bool(true);
36
-    private static final Bool BOTTOM_TABS_ANIMATE_HIDE = new Bool(true);
36
+    private static final Bool BOTTOM_TABS_ANIMATE = new Bool(true);
37 37
     private static final Bool BOTTOM_TABS_VISIBLE = new Bool(true);
38 38
     private static final String BOTTOM_TABS_BADGE = "3";
39 39
     private static final String BOTTOM_TABS_CURRENT_TAB_ID = "ComponentId";
@@ -70,7 +70,7 @@ public class OptionsTest extends BaseTest {
70 70
         assertThat(result.topBarOptions.visible.get()).isEqualTo(TOP_BAR_VISIBLE.get());
71 71
         assertThat(result.topBarOptions.drawBehind.get()).isEqualTo(TOP_BAR_DRAW_BEHIND.get());
72 72
         assertThat(result.topBarOptions.hideOnScroll.get()).isEqualTo(TOP_BAR_HIDE_ON_SCROLL.get());
73
-        assertThat(result.bottomTabsOptions.animateHide.get()).isEqualTo(BOTTOM_TABS_ANIMATE_HIDE.get());
73
+        assertThat(result.bottomTabsOptions.animate.get()).isEqualTo(BOTTOM_TABS_ANIMATE.get());
74 74
         assertThat(result.bottomTabsOptions.visible.get()).isEqualTo(BOTTOM_TABS_VISIBLE.get());
75 75
         assertThat(result.bottomTabsOptions.currentTabId.get()).isEqualTo(BOTTOM_TABS_CURRENT_TAB_ID);
76 76
         assertThat(result.bottomTabsOptions.currentTabIndex.get()).isEqualTo(BOTTOM_TABS_CURRENT_TAB_INDEX.get());
@@ -90,7 +90,7 @@ public class OptionsTest extends BaseTest {
90 90
                 .put("currentTabId", BOTTOM_TABS_CURRENT_TAB_ID)
91 91
                 .put("currentTabIndex", BOTTOM_TABS_CURRENT_TAB_INDEX.get())
92 92
                 .put("visible", BOTTOM_TABS_VISIBLE.get())
93
-                .put("animateHide", BOTTOM_TABS_ANIMATE_HIDE.get());
93
+                .put("animate", BOTTOM_TABS_ANIMATE.get());
94 94
     }
95 95
 
96 96
     @NonNull
@@ -144,12 +144,12 @@ public class OptionsTest extends BaseTest {
144 144
     }
145 145
 
146 146
     @NonNull
147
-    private JSONObject createOtherTabBar() throws JSONException {
147
+    private JSONObject createOtherBottomTabs() throws JSONException {
148 148
         return new JSONObject()
149 149
                 .put("currentTabId", BOTTOM_TABS_CURRENT_TAB_ID)
150 150
                 .put("currentTabIndex", BOTTOM_TABS_CURRENT_TAB_INDEX)
151 151
                 .put("visible", BOTTOM_TABS_VISIBLE)
152
-                .put("animateHide", BOTTOM_TABS_ANIMATE_HIDE)
152
+                .put("animate", BOTTOM_TABS_ANIMATE.get())
153 153
                 .put("tabBadge", BOTTOM_TABS_BADGE);
154 154
     }
155 155
 
@@ -188,7 +188,7 @@ public class OptionsTest extends BaseTest {
188 188
         JSONObject defaultJson = new JSONObject()
189 189
                 .put("topBar", createOtherTopBar())
190 190
                 .put("fab", createOtherFab())
191
-                .put("bottomTabs", createOtherTabBar());
191
+                .put("bottomTabs", createOtherBottomTabs());
192 192
         Options defaultOptions = Options.parse(mockLoader, defaultJson);
193 193
 
194 194
         JSONObject json = new JSONObject()
@@ -209,7 +209,7 @@ public class OptionsTest extends BaseTest {
209 209
     public void topBar_defaultOptions() throws Exception {
210 210
         Options uut = new Options();
211 211
         assertThat(uut.topBarOptions.visible.isFalseOrUndefined()).isTrue();
212
-        assertThat(uut.topBarOptions.animateHide.isTrueOrUndefined()).isTrue();
212
+        assertThat(uut.topBarOptions.animate.isTrueOrUndefined()).isTrue();
213 213
     }
214 214
 
215 215
     @Test

+ 1
- 1
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/OptionsApplyingTest.java View File

@@ -147,7 +147,7 @@ public class OptionsApplyingTest extends BaseTest {
147 147
 
148 148
         Options opts = new Options();
149 149
         opts.topBarOptions.visible = new Bool(false);
150
-        opts.topBarOptions.animateHide = new Bool(false);
150
+        opts.topBarOptions.animate = new Bool(false);
151 151
         uut.mergeOptions(opts);
152 152
 
153 153
         assertThat(stackController.getTopBar().getVisibility()).isEqualTo(View.GONE);

+ 47
- 0
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/StackControllerTest.java View File

@@ -8,8 +8,10 @@ import com.reactnativenavigation.mocks.MockPromise;
8 8
 import com.reactnativenavigation.mocks.SimpleViewController;
9 9
 import com.reactnativenavigation.parse.Options;
10 10
 import com.reactnativenavigation.parse.Text;
11
+import com.reactnativenavigation.parse.params.Bool;
11 12
 import com.reactnativenavigation.utils.ViewHelper;
12 13
 import com.reactnativenavigation.views.ReactComponent;
14
+import com.reactnativenavigation.views.StackLayout;
13 15
 
14 16
 import org.assertj.core.api.iterable.Extractor;
15 17
 import org.junit.Test;
@@ -75,6 +77,30 @@ public class StackControllerTest extends BaseTest {
75 77
         });
76 78
     }
77 79
 
80
+    @Test
81
+    public void pop_layoutHandlesChildWillDisappear() throws Exception {
82
+        final StackLayout[] stackLayout = new StackLayout[1];
83
+        uut = new StackController(activity, "uut", new Options()) {
84
+            @Override
85
+            protected StackLayout createView() {
86
+                stackLayout[0] = spy(super.createView());
87
+                return stackLayout[0];
88
+            }
89
+        };
90
+        uut.push(child1, new MockPromise());
91
+        uut.animatePush(child2, new MockPromise() {
92
+            @Override
93
+            public void resolve(@Nullable Object value) {
94
+                uut.animatePop(new MockPromise() {
95
+                    @Override
96
+                    public void resolve(@Nullable Object value) {
97
+                        verify(stackLayout[0], times(1)).onChildWillDisappear(child2.options, child1.options);
98
+                    }
99
+                });
100
+            }
101
+        });
102
+    }
103
+
78 104
     @Test
79 105
     public void stackOperations() throws Exception {
80 106
         assertThat(uut.peek()).isNull();
@@ -306,6 +332,27 @@ public class StackControllerTest extends BaseTest {
306 332
         verify(child2, times(1)).onViewWillDisappear();
307 333
     }
308 334
 
335
+    @Test
336
+    public void pop_animatesTopBarIfNeeded() throws Exception {
337
+        uut.ensureViewIsCreated();
338
+        uut.getView().setTopBar(spy(uut.getTopBar()));
339
+
340
+        child1.options.topBarOptions.visible = new Bool(false);
341
+        child1.options.topBarOptions.animate = new Bool(false);
342
+        child2.options.topBarOptions.visible = new Bool(true);
343
+        uut.push(child1, new MockPromise());
344
+        child1.onViewAppeared();
345
+
346
+        assertThat(uut.getTopBar().getVisibility()).isEqualTo(View.GONE);
347
+        uut.push(child2, new MockPromise());
348
+        uut.animatePop(new MockPromise() {
349
+            @Override
350
+            public void resolve(@Nullable Object value) {
351
+                verify(uut.getTopBar(), times(1)).hide(child2.options.topBarOptions.animate);
352
+            }
353
+        });
354
+    }
355
+
309 356
     @Test
310 357
     public void popSpecific_CallsDestroyOnPoppedChild() throws Exception {
311 358
         child1 = spy(child1);

+ 9
- 3
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TopTabsViewControllerTest.java View File

@@ -24,6 +24,8 @@ import org.mockito.Mockito;
24 24
 import java.util.ArrayList;
25 25
 import java.util.List;
26 26
 
27
+import javax.annotation.Nullable;
28
+
27 29
 import static org.assertj.core.api.Assertions.assertThat;
28 30
 import static org.mockito.ArgumentMatchers.any;
29 31
 import static org.mockito.ArgumentMatchers.eq;
@@ -209,7 +211,7 @@ public class TopTabsViewControllerTest extends BaseTest {
209 211
     }
210 212
 
211 213
     @Test
212
-    public void applyOptions_tabsAreRemovedBeforeViewDisappears() throws Exception {
214
+    public void applyOptions_tabsAreRemovedAfterViewDisappears() throws Exception {
213 215
         parentController.getView().removeAllViews();
214 216
 
215 217
         StackController stackController = spy(new StackController(activity, "stack", new Options()));
@@ -228,8 +230,12 @@ public class TopTabsViewControllerTest extends BaseTest {
228 230
         uut.onViewAppeared();
229 231
 
230 232
         assertThat(ViewHelper.isVisible(stackController.getTopBar().getTopTabs())).isTrue();
231
-        stackController.pop(new MockPromise());
232
-        assertThat(ViewHelper.isVisible(stackController.getTopBar().getTopTabs())).isFalse();
233
+        stackController.animatePop(new MockPromise() {
234
+            @Override
235
+            public void resolve(@Nullable Object value) {
236
+                assertThat(ViewHelper.isVisible(stackController.getTopBar().getTopTabs())).isFalse();
237
+            }
238
+        });
233 239
     }
234 240
 
235 241
     @Test

+ 1
- 7
playground/src/app.js View File

@@ -31,13 +31,7 @@ function start() {
31 31
               name: 'navigation.playground.WelcomeScreen'
32 32
             }
33 33
           }
34
-        ],
35
-        options: {
36
-          topBar: {
37
-            visible: false,
38
-            animateHide: false
39
-          }
40
-        }
34
+        ]
41 35
       }
42 36
     });
43 37
   });

+ 2
- 2
playground/src/screens/OptionsScreen.js View File

@@ -191,7 +191,7 @@ class OptionsScreen extends Component {
191 191
     Navigation.setOptions(this.props.componentId, {
192 192
       topBar: {
193 193
         visible: true,
194
-        animateHide: true
194
+        animate: true
195 195
       }
196 196
     });
197 197
   }
@@ -200,7 +200,7 @@ class OptionsScreen extends Component {
200 200
     Navigation.setOptions(this.props.componentId, {
201 201
       topBar: {
202 202
         visible: false,
203
-        animateHide: true
203
+        animate: true
204 204
       }
205 205
     });
206 206
   }

+ 1
- 1
playground/src/screens/TextScreen.js View File

@@ -70,7 +70,7 @@ class TextScreen extends Component {
70 70
       bottomTabs: {
71 71
         currentTabIndex: 1,
72 72
         visible: false,
73
-        animateHide: true
73
+        animate: true
74 74
       }
75 75
     });
76 76
   }

+ 4
- 1
playground/src/screens/WelcomeScreen.js View File

@@ -10,7 +10,10 @@ class WelcomeScreen extends Component {
10 10
   static get options() {
11 11
     return {
12 12
       topBar: {
13
-        largeTitle: false
13
+        largeTitle: false,
14
+        drawBehind: true,
15
+        visible: false,
16
+        animate: false
14 17
       }
15 18
     };
16 19
   }