소스 검색

Mount all stack children (#6194)

This commit somewhat consolidates how stack children are mounted.

On Android, until now, only the top child in a stack was mounted when the stack became visible or when setStackRoot() was called. When popping the stack the new current child would be mounted when it was attached. This caused flickering when popping the stack as the pop animation started before the child finished mounting.

Now all children will be mounted together after the top child is mounted :)

Co-authored-by: Yogev Ben David <yogev132@gmail.com>
Guy Carmeli 4 년 전
부모
커밋
a1beebe74b
No account linked to committer's email address

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/react/ReactView.java 파일 보기

@@ -42,7 +42,7 @@ public class ReactView extends ReactRootView implements IReactView, Renderable {
42 42
         start();
43 43
     }
44 44
 
45
-    private void start() {
45
+    public void start() {
46 46
         if (isAttachedToReactInstance) return;
47 47
         isAttachedToReactInstance = true;
48 48
 		final Bundle opts = new Bundle();

+ 5
- 5
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ComponentViewController.java 파일 보기

@@ -9,7 +9,6 @@ import com.reactnativenavigation.presentation.ComponentPresenter;
9 9
 import com.reactnativenavigation.presentation.Presenter;
10 10
 import com.reactnativenavigation.utils.StatusBarUtils;
11 11
 import com.reactnativenavigation.views.ComponentLayout;
12
-import com.reactnativenavigation.views.ReactComponent;
13 12
 
14 13
 import androidx.annotation.NonNull;
15 14
 import androidx.core.view.ViewCompat;
@@ -22,10 +21,6 @@ public class ComponentViewController extends ChildController<ComponentLayout> {
22 21
     private ComponentPresenter presenter;
23 22
     private final ReactViewCreator viewCreator;
24 23
 
25
-    ReactComponent getComponent() {
26
-        return view;
27
-    }
28
-
29 24
     public ComponentViewController(final Activity activity,
30 25
                                    final ChildControllersRegistry childRegistry,
31 26
                                    final String id,
@@ -40,6 +35,11 @@ public class ComponentViewController extends ChildController<ComponentLayout> {
40 35
         this.presenter = componentPresenter;
41 36
     }
42 37
 
38
+    @Override
39
+    public void start() {
40
+        if (!isDestroyed()) getView().start();
41
+    }
42
+
43 43
     @Override
44 44
     public String getCurrentComponentName() {
45 45
         return this.componentName;

+ 6
- 7
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/IdStack.java 파일 보기

@@ -1,17 +1,16 @@
1 1
 package com.reactnativenavigation.viewcontrollers;
2 2
 
3
-import androidx.annotation.NonNull;
4
-
5 3
 import com.reactnativenavigation.utils.StringUtils;
6 4
 
7 5
 import java.util.ArrayList;
8
-import java.util.Collection;
9 6
 import java.util.HashMap;
10 7
 import java.util.Iterator;
8
+import java.util.List;
11 9
 import java.util.Map;
12 10
 
13
-import static com.reactnativenavigation.utils.CollectionUtils.last;
14
-import static com.reactnativenavigation.utils.CollectionUtils.removeLast;
11
+import androidx.annotation.NonNull;
12
+
13
+import static com.reactnativenavigation.utils.CollectionUtils.*;
15 14
 
16 15
 public class IdStack<E> implements Iterable<String> {
17 16
 
@@ -84,8 +83,8 @@ public class IdStack<E> implements Iterable<String> {
84 83
 	}
85 84
 
86 85
 
87
-	public Collection<E> values() {
88
-		return map.values();
86
+	public List<E> values() {
87
+		return map(deque, map::get);
89 88
 	}
90 89
 
91 90
     public void remove(Iterator<String> iterator, String id) {

+ 4
- 0
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ViewController.java 파일 보기

@@ -339,6 +339,10 @@ public abstract class ViewController<T extends ViewGroup> implements ViewTreeObs
339 339
         );
340 340
     }
341 341
 
342
+    public void start() {
343
+
344
+    }
345
+
342 346
     void applyOnController(ViewController controller, Func1<ViewController> task) {
343 347
         if (controller != null) task.run(controller);
344 348
     }

+ 10
- 0
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/StackController.java 파일 보기

@@ -26,6 +26,7 @@ import com.reactnativenavigation.views.StackLayout;
26 26
 import com.reactnativenavigation.views.stack.StackBehaviour;
27 27
 import com.reactnativenavigation.views.topbar.TopBar;
28 28
 
29
+import java.util.ArrayList;
29 30
 import java.util.Collection;
30 31
 import java.util.Iterator;
31 32
 import java.util.List;
@@ -214,6 +215,7 @@ public class StackController extends ParentController<StackLayout> {
214 215
                             backButtonHelper.addToPushedChild(children.get(i));
215 216
                         }
216 217
                     }
218
+                    startChildrenBellowTopChild();
217 219
                 }
218 220
                 listener.onSuccess(childId);
219 221
             }
@@ -360,10 +362,18 @@ public class StackController extends ParentController<StackLayout> {
360 362
         if (isEmpty()) return;
361 363
         ViewGroup child = peek().getView();
362 364
         child.setId(CompatUtils.generateViewId());
365
+        peek().addOnAppearedListener(this::startChildrenBellowTopChild);
363 366
         presenter.applyInitialChildLayoutOptions(resolveCurrentOptions());
364 367
         stackLayout.addView(child, 0, matchParentWithBehaviour(new StackBehaviour(this)));
365 368
     }
366 369
 
370
+    private void startChildrenBellowTopChild() {
371
+        ArrayList<ViewController> children = new ArrayList(getChildControllers());
372
+        for (int i = children.size() - 2; i >= 0; i--) {
373
+            children.get(i).start();
374
+        }
375
+    }
376
+
367 377
     private void onNavigationButtonPressed(String buttonId) {
368 378
         if (Constants.BACK_BUTTON_ID.equals(buttonId)) {
369 379
             pop(Options.EMPTY, new CommandListenerAdapter());

+ 4
- 0
lib/android/app/src/main/java/com/reactnativenavigation/views/ComponentLayout.java 파일 보기

@@ -45,6 +45,10 @@ public class ComponentLayout extends CoordinatorLayout implements ReactComponent
45 45
         reactView.destroy();
46 46
     }
47 47
 
48
+    public void start() {
49
+        reactView.start();
50
+    }
51
+
48 52
 	public void sendComponentStart() {
49 53
 		reactView.sendComponentStart(ComponentType.Component);
50 54
 	}

+ 1
- 1
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/IdStackTest.java 파일 보기

@@ -109,6 +109,6 @@ public class IdStackTest extends BaseTest {
109 109
         assertThat(uut.values()).isNotNull().isEmpty();
110 110
         uut.push("123", 123);
111 111
         uut.push("456", 456);
112
-        assertThat(uut.values()).isNotNull().containsExactlyInAnyOrder(123, 456);
112
+        assertThat(uut.values()).isNotNull().containsSequence(123, 456);
113 113
     }
114 114
 }

+ 28
- 4
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/StackControllerTest.java 파일 보기

@@ -12,9 +12,9 @@ import com.reactnativenavigation.TestUtils;
12 12
 import com.reactnativenavigation.anim.NavigationAnimator;
13 13
 import com.reactnativenavigation.mocks.ImageLoaderMock;
14 14
 import com.reactnativenavigation.mocks.SimpleViewController;
15
+import com.reactnativenavigation.mocks.TitleBarButtonCreatorMock;
15 16
 import com.reactnativenavigation.mocks.TitleBarReactViewCreatorMock;
16 17
 import com.reactnativenavigation.mocks.TopBarBackgroundViewCreatorMock;
17
-import com.reactnativenavigation.mocks.TitleBarButtonCreatorMock;
18 18
 import com.reactnativenavigation.parse.AnimationOptions;
19 19
 import com.reactnativenavigation.parse.NestedAnimationsOptions;
20 20
 import com.reactnativenavigation.parse.Options;
@@ -59,6 +59,7 @@ import java.util.List;
59 59
 
60 60
 import androidx.coordinatorlayout.widget.CoordinatorLayout;
61 61
 
62
+import static com.reactnativenavigation.utils.ObjectUtils.take;
62 63
 import static com.reactnativenavigation.utils.ViewUtils.topMargin;
63 64
 import static org.assertj.core.api.Java6Assertions.assertThat;
64 65
 import static org.mockito.ArgumentMatchers.any;
@@ -82,6 +83,7 @@ public class StackControllerTest extends BaseTest {
82 83
     private ViewController child1a;
83 84
     private ViewController child2;
84 85
     private ViewController child3;
86
+    private SimpleViewController.SimpleView child3View;
85 87
     private ViewController child4;
86 88
     private NavigationAnimator animator;
87 89
     private TopBarController topBarController;
@@ -108,13 +110,22 @@ public class StackControllerTest extends BaseTest {
108 110
                     new Options()
109 111
                 )
110 112
         );
113
+        createChildren();
114
+        uut = createStack();
115
+        activity.setContentView(uut.getView());
116
+    }
117
+
118
+    private void createChildren() {
111 119
         child1 = spy(new SimpleViewController(activity, childRegistry, "child1", new Options()));
112 120
         child1a = spy(new SimpleViewController(activity, childRegistry, "child1", new Options()));
113 121
         child2 = spy(new SimpleViewController(activity, childRegistry, "child2", new Options()));
114
-        child3 = spy(new SimpleViewController(activity, childRegistry, "child3", new Options()));
122
+        child3 = spy(new SimpleViewController(activity, childRegistry, "child3", new Options()) {
123
+            @Override
124
+            protected SimpleView createView() {
125
+                return take(child3View, super.createView());
126
+            }
127
+        });
115 128
         child4 = spy(new SimpleViewController(activity, childRegistry, "child4", new Options()));
116
-        uut = createStack();
117
-        activity.setContentView(uut.getView());
118 129
     }
119 130
 
120 131
     @Test
@@ -394,6 +405,19 @@ public class StackControllerTest extends BaseTest {
394 405
         assertContainsOnlyId(child1a.getId());
395 406
     }
396 407
 
408
+    @Test
409
+    public void setRoot_topScreenIsStartedThenTheRest() {
410
+        disablePushAnimation(child1, child2, child3);
411
+        child3View = spy(new SimpleViewController.SimpleView(activity));
412
+
413
+        uut.setRoot(Arrays.asList(child1, child2, child3), new CommandListenerAdapter());
414
+        ShadowLooper.idleMainLooper();
415
+        InOrder inOrder = inOrder(child3View, child2, child1);
416
+        inOrder.verify(child3View).start();
417
+        inOrder.verify(child2).start();
418
+        inOrder.verify(child1).start();
419
+    }
420
+
397 421
     @Test
398 422
     public synchronized void pop() {
399 423
         disablePushAnimation(child1, child2);