Browse Source

Hide keyboard when view is removed from screen

This commit includes two major changes

1. Move all calls to private react-native API to a single class and
change access modifier of the ReactRootView to private.

2. Hide soft keyboard when a view is removed from screen. This
potentially fixes a bug we encountered internally where react
failed to render the shadow DOM properly, when popping a screen
while the soft keyboard was displayed.
Guy Carmeli 8 years ago
parent
commit
5ea4ec800e

+ 36
- 8
android/app/src/main/java/com/reactnativenavigation/views/RctView.java View File

@@ -2,6 +2,7 @@ package com.reactnativenavigation.views;
2 2
 
3 3
 import android.os.Bundle;
4 4
 import android.view.ViewTreeObserver;
5
+import android.view.inputmethod.InputMethodManager;
5 6
 import android.widget.FrameLayout;
6 7
 
7 8
 import com.facebook.react.ReactInstanceManager;
@@ -9,6 +10,9 @@ import com.facebook.react.ReactRootView;
9 10
 import com.reactnativenavigation.activities.BaseReactActivity;
10 11
 import com.reactnativenavigation.core.objects.Screen;
11 12
 import com.reactnativenavigation.utils.BridgeUtils;
13
+import com.reactnativenavigation.utils.ReflectionUtils;
14
+
15
+import static android.content.Context.INPUT_METHOD_SERVICE;
12 16
 
13 17
 /**
14 18
  * Created by guyc on 10/03/16.
@@ -27,14 +31,6 @@ public class RctView extends FrameLayout {
27 31
         public void onDisplayed();
28 32
     }
29 33
 
30
-    public ReactRootView getReactRootView() {
31
-        return mReactRootView;
32
-    }
33
-
34
-    public RctView(BaseReactActivity ctx, ReactInstanceManager rctInstanceManager, Screen screen) {
35
-        this(ctx, rctInstanceManager, screen, null);
36
-    }
37
-
38 34
     @SuppressWarnings("unchecked")
39 35
     public RctView(BaseReactActivity ctx, ReactInstanceManager rctInstanceManager, Screen screen,
40 36
                    final OnDisplayedListener onDisplayedListener) {
@@ -67,5 +63,37 @@ public class RctView extends FrameLayout {
67 63
 
68 64
         addView(mReactRootView);
69 65
     }
66
+
67
+    /**
68
+     * Must be called before view is removed from screen, but will be added again later. Setting mAttachScheduled
69
+     * to true will prevent the component from getting unmounted once view is detached from screen.
70
+     */
71
+    public void onTemporallyRemovedFromScreen() {
72
+        // Hack in order to prevent the react view from getting unmounted
73
+        ReflectionUtils.setBooleanField(this, "mAttachScheduled", true);
74
+        dismissSoftKeyBoard();
75
+    }
76
+
77
+    /**
78
+     * Must be called before view is removed from screen inorder to ensure onDetachedFromScreen is properly
79
+     * executed and componentWillUnmount is called
80
+     */
81
+    public void onRemovedFromScreen() {
82
+        ReflectionUtils.setBooleanField(this, "mAttachScheduled", false);
83
+        dismissSoftKeyBoard();
84
+    }
85
+
86
+    private void dismissSoftKeyBoard() {
87
+        InputMethodManager inputManager = (InputMethodManager) getContext().getSystemService(INPUT_METHOD_SERVICE);
88
+        inputManager.hideSoftInputFromWindow(getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
89
+    }
90
+
91
+    /**
92
+     * Must be called before view is added again to screen inorder to ensure onDetachedFromScreen is properly
93
+     * executed and componentWillUnmount is called
94
+     */
95
+    public void onReaddedToScreen() {
96
+        ReflectionUtils.setBooleanField(this, "mAttachScheduled", false);
97
+    }
70 98
 }
71 99
 

+ 9
- 13
android/app/src/main/java/com/reactnativenavigation/views/ScreenStack.java View File

@@ -7,11 +7,9 @@ import android.view.ViewGroup;
7 7
 import android.widget.FrameLayout;
8 8
 
9 9
 import com.facebook.react.ReactInstanceManager;
10
-import com.facebook.react.ReactRootView;
11 10
 import com.reactnativenavigation.activities.BaseReactActivity;
12 11
 import com.reactnativenavigation.core.RctManager;
13 12
 import com.reactnativenavigation.core.objects.Screen;
14
-import com.reactnativenavigation.utils.ReflectionUtils;
15 13
 
16 14
 import java.util.Stack;
17 15
 
@@ -60,7 +58,7 @@ public class ScreenStack extends FrameLayout {
60 58
         if (oldView != null) {
61 59
             addView(view, MATCH_PARENT, MATCH_PARENT);
62 60
 
63
-            ReflectionUtils.setBooleanField(oldView.getReactRootView(), "mAttachScheduled", true);
61
+            oldView.onTemporallyRemovedFromScreen();
64 62
             getLayoutTransition().setStartDelay(LayoutTransition.DISAPPEARING, DISAPPEAR_ANIMATION_DELAY);
65 63
             removeView(oldView);
66 64
             getLayoutTransition().setStartDelay(LayoutTransition.DISAPPEARING, 0);
@@ -78,7 +76,7 @@ public class ScreenStack extends FrameLayout {
78 76
         ScreenView popped = mStack.pop();
79 77
         addView(mStack.peek().view, 0);
80 78
 
81
-        ReflectionUtils.setBooleanField(popped.view.getReactRootView(), "mAttachScheduled", false);
79
+        popped.view.onRemovedFromScreen();
82 80
         removeView(popped.view);
83 81
         return popped.screen;
84 82
     }
@@ -91,7 +89,7 @@ public class ScreenStack extends FrameLayout {
91 89
         ScreenView oldScreenView = null;
92 90
         while (getStackSize() > 1) {
93 91
             ScreenView popped = mStack.pop();
94
-            ReflectionUtils.setBooleanField(popped.view.getReactRootView(), "mAttachScheduled", false);
92
+            popped.view.onRemovedFromScreen();
95 93
             removeView(popped.view);
96 94
             if (oldScreenView == null) {
97 95
                 oldScreenView = popped;
@@ -116,11 +114,11 @@ public class ScreenStack extends FrameLayout {
116 114
         ScreenView oldScreenView = null;
117 115
         if (!mStack.isEmpty()) {
118 116
             while (getStackSize() > 0) {
119
-                ScreenView screenView = mStack.pop();
120
-                ReflectionUtils.setBooleanField(screenView.view.getReactRootView(), "mAttachScheduled", false);
121
-                removeView(screenView.view);
117
+                ScreenView popped = mStack.pop();
118
+                popped.view.onRemovedFromScreen();
119
+                removeView(popped.view);
122 120
                 if (oldScreenView == null) {
123
-                    oldScreenView = screenView;
121
+                    oldScreenView = popped;
124 122
                 }
125 123
             }
126 124
         }
@@ -151,8 +149,7 @@ public class ScreenStack extends FrameLayout {
151 149
      * Remove the ScreenStack from {@code parent} while preventing all child react views from getting unmounted
152 150
      */
153 151
     public void removeFromScreen(ViewGroup parent) {
154
-        ReactRootView view = mStack.peek().view.getReactRootView();
155
-        ReflectionUtils.setBooleanField(view, "mAttachScheduled", true);
152
+        mStack.peek().view.onTemporallyRemovedFromScreen();
156 153
 
157 154
         parent.removeView(this);
158 155
     }
@@ -161,8 +158,7 @@ public class ScreenStack extends FrameLayout {
161 158
      * Add ScreenStack to {@code parent}
162 159
      */
163 160
     public void addToScreen(ViewGroup parent) {
164
-        ReactRootView view = mStack.peek().view.getReactRootView();
165
-        ReflectionUtils.setBooleanField(view, "mAttachScheduled", false);
161
+        mStack.peek().view.onReaddedToScreen();
166 162
 
167 163
         parent.addView(this, new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
168 164
     }