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
 
2
 
3
 import android.os.Bundle;
3
 import android.os.Bundle;
4
 import android.view.ViewTreeObserver;
4
 import android.view.ViewTreeObserver;
5
+import android.view.inputmethod.InputMethodManager;
5
 import android.widget.FrameLayout;
6
 import android.widget.FrameLayout;
6
 
7
 
7
 import com.facebook.react.ReactInstanceManager;
8
 import com.facebook.react.ReactInstanceManager;
9
 import com.reactnativenavigation.activities.BaseReactActivity;
10
 import com.reactnativenavigation.activities.BaseReactActivity;
10
 import com.reactnativenavigation.core.objects.Screen;
11
 import com.reactnativenavigation.core.objects.Screen;
11
 import com.reactnativenavigation.utils.BridgeUtils;
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
  * Created by guyc on 10/03/16.
18
  * Created by guyc on 10/03/16.
27
         public void onDisplayed();
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
     @SuppressWarnings("unchecked")
34
     @SuppressWarnings("unchecked")
39
     public RctView(BaseReactActivity ctx, ReactInstanceManager rctInstanceManager, Screen screen,
35
     public RctView(BaseReactActivity ctx, ReactInstanceManager rctInstanceManager, Screen screen,
40
                    final OnDisplayedListener onDisplayedListener) {
36
                    final OnDisplayedListener onDisplayedListener) {
67
 
63
 
68
         addView(mReactRootView);
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
 import android.widget.FrameLayout;
7
 import android.widget.FrameLayout;
8
 
8
 
9
 import com.facebook.react.ReactInstanceManager;
9
 import com.facebook.react.ReactInstanceManager;
10
-import com.facebook.react.ReactRootView;
11
 import com.reactnativenavigation.activities.BaseReactActivity;
10
 import com.reactnativenavigation.activities.BaseReactActivity;
12
 import com.reactnativenavigation.core.RctManager;
11
 import com.reactnativenavigation.core.RctManager;
13
 import com.reactnativenavigation.core.objects.Screen;
12
 import com.reactnativenavigation.core.objects.Screen;
14
-import com.reactnativenavigation.utils.ReflectionUtils;
15
 
13
 
16
 import java.util.Stack;
14
 import java.util.Stack;
17
 
15
 
60
         if (oldView != null) {
58
         if (oldView != null) {
61
             addView(view, MATCH_PARENT, MATCH_PARENT);
59
             addView(view, MATCH_PARENT, MATCH_PARENT);
62
 
60
 
63
-            ReflectionUtils.setBooleanField(oldView.getReactRootView(), "mAttachScheduled", true);
61
+            oldView.onTemporallyRemovedFromScreen();
64
             getLayoutTransition().setStartDelay(LayoutTransition.DISAPPEARING, DISAPPEAR_ANIMATION_DELAY);
62
             getLayoutTransition().setStartDelay(LayoutTransition.DISAPPEARING, DISAPPEAR_ANIMATION_DELAY);
65
             removeView(oldView);
63
             removeView(oldView);
66
             getLayoutTransition().setStartDelay(LayoutTransition.DISAPPEARING, 0);
64
             getLayoutTransition().setStartDelay(LayoutTransition.DISAPPEARING, 0);
78
         ScreenView popped = mStack.pop();
76
         ScreenView popped = mStack.pop();
79
         addView(mStack.peek().view, 0);
77
         addView(mStack.peek().view, 0);
80
 
78
 
81
-        ReflectionUtils.setBooleanField(popped.view.getReactRootView(), "mAttachScheduled", false);
79
+        popped.view.onRemovedFromScreen();
82
         removeView(popped.view);
80
         removeView(popped.view);
83
         return popped.screen;
81
         return popped.screen;
84
     }
82
     }
91
         ScreenView oldScreenView = null;
89
         ScreenView oldScreenView = null;
92
         while (getStackSize() > 1) {
90
         while (getStackSize() > 1) {
93
             ScreenView popped = mStack.pop();
91
             ScreenView popped = mStack.pop();
94
-            ReflectionUtils.setBooleanField(popped.view.getReactRootView(), "mAttachScheduled", false);
92
+            popped.view.onRemovedFromScreen();
95
             removeView(popped.view);
93
             removeView(popped.view);
96
             if (oldScreenView == null) {
94
             if (oldScreenView == null) {
97
                 oldScreenView = popped;
95
                 oldScreenView = popped;
116
         ScreenView oldScreenView = null;
114
         ScreenView oldScreenView = null;
117
         if (!mStack.isEmpty()) {
115
         if (!mStack.isEmpty()) {
118
             while (getStackSize() > 0) {
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
                 if (oldScreenView == null) {
120
                 if (oldScreenView == null) {
123
-                    oldScreenView = screenView;
121
+                    oldScreenView = popped;
124
                 }
122
                 }
125
             }
123
             }
126
         }
124
         }
151
      * Remove the ScreenStack from {@code parent} while preventing all child react views from getting unmounted
149
      * Remove the ScreenStack from {@code parent} while preventing all child react views from getting unmounted
152
      */
150
      */
153
     public void removeFromScreen(ViewGroup parent) {
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
         parent.removeView(this);
154
         parent.removeView(this);
158
     }
155
     }
161
      * Add ScreenStack to {@code parent}
158
      * Add ScreenStack to {@code parent}
162
      */
159
      */
163
     public void addToScreen(ViewGroup parent) {
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
         parent.addView(this, new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
163
         parent.addView(this, new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
168
     }
164
     }