소스 검색

Android back handler (#2282)

* Reorder dependencies

Keep vs code happy

* Make markdown files readable on MacDown

* BackHandler compatibility

Give precedence to react's BackHandler when hardware back button is pressed

* f

* Update test

* Restore deps
Guy Carmeli 6 년 전
부모
커밋
5971384ab3
No account linked to committer's email address

+ 22
- 0
AndroidE2E/app/src/androidTest/java/com/reactnativenavigation/e2e/androide2e/BackHandlerTest.java 파일 보기

@@ -0,0 +1,22 @@
1
+package com.reactnativenavigation.e2e.androide2e;
2
+
3
+import android.support.test.uiautomator.By;
4
+
5
+import org.junit.Test;
6
+
7
+public class BackHandlerTest extends BaseTest {
8
+    @Test
9
+    public void overrideHardwareBackButton() throws Exception {
10
+        elementByText("BACK HANDLER").click();
11
+        assertExists(By.text("Back Handler Screen"));
12
+
13
+        elementByText("ADD BACK HANDLER").click();
14
+        device().pressBack();
15
+        assertExists(By.text("Back Handler Screen"));
16
+
17
+
18
+        elementByText("REMOVE BACK HANDLER").click();
19
+        device().pressBack();
20
+        assertMainShown();
21
+    }
22
+}

+ 2
- 2
AndroidE2E/app/src/androidTest/java/com/reactnativenavigation/e2e/androide2e/BaseTest.java 파일 보기

@@ -24,8 +24,8 @@ import static org.assertj.core.api.Java6Assertions.assertThat;
24 24
 
25 25
 @RunWith(AndroidJUnit4.class)
26 26
 public abstract class BaseTest {
27
-	public static final String PACKAGE_NAME = "com.reactnativenavigation.playground";
28
-	public static final long TIMEOUT = 60000;
27
+	static final String PACKAGE_NAME = "com.reactnativenavigation.playground";
28
+	private static final long TIMEOUT = 60000;
29 29
 
30 30
 	@Before
31 31
 	public void beforeEach() throws Exception {

+ 8
- 0
docs/docs/usage.md 파일 보기

@@ -21,12 +21,14 @@ Navigation.events().onAppLaunched(() => {
21 21
 
22 22
 ### registerContainer(screenID, generator)
23 23
 Every screen component in your app must be registered with a unique name. The component itself is a traditional React component extending React.Component.
24
+
24 25
 ```js
25 26
 Navigation.registerContainer(`navigation.playground.WelcomeScreen`, () => WelcomeScreen);
26 27
 ```
27 28
 
28 29
 ### setRoot({params})
29 30
 Start a Single page app with two side menus:
31
+
30 32
 ```js
31 33
 Navigation.setRoot({
32 34
   container: {
@@ -53,6 +55,7 @@ Navigation.setRoot({
53 55
 });
54 56
 ```
55 57
 Start a tab based app:
58
+
56 59
 ```js
57 60
 Navigation.setRoot({
58 61
   bottomTabs: [
@@ -80,6 +83,7 @@ Navigation.setRoot({
80 83
 
81 84
 ### push(params)
82 85
 Push a new screen into this screen's navigation stack.
86
+
83 87
 ```js
84 88
 Navigation.push(this.props.containerId, {
85 89
   name: 'navigation.playground.PushedScreen',
@@ -88,6 +92,7 @@ Navigation.push(this.props.containerId, {
88 92
 ```
89 93
 ### pop(containerId)
90 94
 Pop the top screen from this screen's navigation stack.
95
+
91 96
 ```js
92 97
 Navigation.pop(this.props.containerId);
93 98
 ```
@@ -97,11 +102,13 @@ Navigation.popTo(previousScreenId);
97 102
 ```
98 103
 ### popToRoot()
99 104
 Pop all the screens until the root from this screen's navigation stack
105
+
100 106
 ```js
101 107
 Navigation.popToRoot(this.props.containerId);
102 108
 ```
103 109
 ### showModal(params = {})
104 110
 Show a screen as a modal.
111
+
105 112
 ```js
106 113
 Navigation.showModal({
107 114
   container: {
@@ -114,6 +121,7 @@ Navigation.showModal({
114 121
 ```
115 122
 ### dismissModal(containerId)
116 123
 Dismiss modal.
124
+
117 125
 ```js
118 126
 Navigation.dismissModal(this.props.containerId);
119 127
 ```

+ 10
- 0
docs/docs/v1tov2diff.md 파일 보기

@@ -188,12 +188,14 @@ Navigation.events().onAppLaunched(() => {
188 188
 
189 189
 #### registerContainer(screenID, generator)
190 190
 Every screen component in your app must be registered with a unique name. The component itself is a traditional React component extending React.Component.
191
+
191 192
 ```js
192 193
 Navigation.registerContainer(`navigation.playground.WelcomeScreen`, () => WelcomeScreen);
193 194
 ```
194 195
 
195 196
 #### setRoot({params})
196 197
 Start a Single page app with two side menus:
198
+
197 199
 ```js
198 200
 Navigation.setRoot({
199 201
       container: {
@@ -220,6 +222,7 @@ Navigation.setRoot({
220 222
     });
221 223
 ```
222 224
 Start a tab based app:
225
+
223 226
 ```js
224 227
 Navigation.setRoot({
225 228
       tabs: [
@@ -247,6 +250,7 @@ Navigation.setRoot({
247 250
 
248 251
 #### push(params)
249 252
 Push a new screen into this screen's navigation stack.
253
+
250 254
 ```js
251 255
 Navigation.push(this.props.containerId, {
252 256
       name: 'navigation.playground.PushedScreen',
@@ -255,20 +259,24 @@ Navigation.push(this.props.containerId, {
255 259
 ```
256 260
 #### pop(containerId)
257 261
 Pop the top screen from this screen's navigation stack.
262
+
258 263
 ```js
259 264
 Navigation.pop(this.props.containerId);
260 265
 ```
261 266
 #### popTo(params)
267
+
262 268
 ```js
263 269
 Navigation.popTo(this.props.containerId, this.props.previousScreenIds[0]);
264 270
 ```
265 271
 #### popToRoot()
266 272
 Pop all the screens until the root from this screen's navigation stack
273
+
267 274
 ```js
268 275
 Navigation.popToRoot(this.props.containerId);
269 276
 ```
270 277
 #### showModal(params = {})
271 278
 Show a screen as a modal.
279
+
272 280
 ```js
273 281
 Navigation.showModal({
274 282
       container: {
@@ -281,11 +289,13 @@ Navigation.showModal({
281 289
 ```
282 290
 #### dismissModal(containerId)
283 291
 Dismiss modal.
292
+
284 293
 ```js
285 294
 Navigation.dismissModal(this.props.containerId);
286 295
 ```
287 296
 #### dismissAllModals()
288 297
 Dismiss all the current modals at the same time.
298
+
289 299
 ```js
290 300
 Navigation.dismissAllModals();
291 301
 ```

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

@@ -41,14 +41,14 @@ public class NavigationActivity extends AppCompatActivity implements DefaultHard
41 41
 
42 42
 	@Override
43 43
 	public void invokeDefaultOnBackPressed() {
44
-		onBackPressed();
44
+        if (!navigator.handleBack()) {
45
+		    super.onBackPressed();
46
+        }
45 47
 	}
46 48
 
47 49
 	@Override
48 50
 	public void onBackPressed() {
49
-		if (!navigator.handleBack()) {
50
-			super.onBackPressed();
51
-		}
51
+        app().getReactGateway().onBackPressed();
52 52
 	}
53 53
 
54 54
 	@Override

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

@@ -46,4 +46,8 @@ public class ReactGateway {
46 46
 	public boolean onKeyUp(final int keyCode) {
47 47
 		return jsDevReloadHandler.onKeyUp(keyCode);
48 48
 	}
49
+
50
+    public void onBackPressed() {
51
+	    reactNativeHost.getReactInstanceManager().onBackPressed();
52
+    }
49 53
 }

+ 75
- 0
playground/src/containers/BackHandlerScreen.js 파일 보기

@@ -0,0 +1,75 @@
1
+const React = require('react');
2
+const { Component } = require('react');
3
+
4
+const { View, Text, Button, BackHandler } = require('react-native');
5
+
6
+class BackHandlerScreen extends Component {
7
+  static get navigationOptions() {
8
+    return {
9
+      topBar: {
10
+        title: 'Back Handler',
11
+        textColor: 'black',
12
+        textFontSize: 16
13
+      }
14
+    };
15
+  }
16
+
17
+  constructor(props) {
18
+    super(props);
19
+    this.addBackHandler = this.addBackHandler.bind(this);
20
+    this.removeBackHandler = this.removeBackHandler.bind(this);
21
+    this.backHandler = () => {
22
+      this.setState({
23
+        backPress: 'Back button pressed!'
24
+      });
25
+      return true;
26
+    };
27
+    this.state = {
28
+      backPress: ''
29
+    };
30
+  }
31
+
32
+  render() {
33
+    return (
34
+      <View style={styles.root}>
35
+        <Text style={styles.h1}>{`Back Handler Screen`}</Text>
36
+        <Text style={styles.h2}>{this.state.backPress}</Text>
37
+        <Button title="add back handler" onPress={this.addBackHandler} />
38
+        <Button title="remove back handler" onPress={this.removeBackHandler} />
39
+      </View>
40
+    );
41
+  }
42
+
43
+  addBackHandler() {
44
+    BackHandler.addEventListener('hardwareBackPress', this.backHandler);
45
+  }
46
+
47
+  removeBackHandler() {
48
+    BackHandler.removeEventListener('hardwareBackPress', this.backHandler);
49
+  }
50
+
51
+  componentWillUnmount() {
52
+    BackHandler.removeEventListener('hardwareBackPress', this.backHandler);
53
+  }
54
+}
55
+
56
+const styles = {
57
+  root: {
58
+    flex: 1,
59
+    backgroundColor: 'white',
60
+    justifyContent: 'center',
61
+    alignItems: 'center'
62
+  },
63
+  h2: {
64
+    fontSize: 12,
65
+    textAlign: 'center',
66
+    margin: 10
67
+  },
68
+  footer: {
69
+    fontSize: 10,
70
+    color: '#888',
71
+    marginTop: 10
72
+  }
73
+};
74
+
75
+module.exports = BackHandlerScreen;

+ 8
- 0
playground/src/containers/WelcomeScreen.js 파일 보기

@@ -12,6 +12,7 @@ class WelcomeScreen extends Component {
12 12
     this.onClickLifecycleScreen = this.onClickLifecycleScreen.bind(this);
13 13
     this.onClickPushOptionsScreen = this.onClickPushOptionsScreen.bind(this);
14 14
     this.onClickPushOrientationMenuScreen = this.onClickPushOrientationMenuScreen.bind(this);
15
+    this.onClickBackHandler = this.onClickBackHandler.bind(this);
15 16
   }
16 17
 
17 18
   render() {
@@ -23,6 +24,7 @@ class WelcomeScreen extends Component {
23 24
         <Button title="Push Lifecycle Screen" onPress={this.onClickLifecycleScreen} />
24 25
         <Button title="Push" onPress={this.onClickPush} />
25 26
         <Button title="Push Options Screen" onPress={this.onClickPushOptionsScreen} />
27
+        <Button title="Back Handler" onPress={this.onClickBackHandler} />
26 28
         <Button title="Show Modal" onPress={this.onClickShowModal} />
27 29
         <Button title="Show Redbox" onPress={this.onClickShowRedbox} />
28 30
         <Button title="Orientation" onPress={this.onClickPushOrientationMenuScreen} />
@@ -134,6 +136,12 @@ class WelcomeScreen extends Component {
134 136
     });
135 137
   }
136 138
 
139
+  onClickBackHandler() {
140
+    Navigation.push(this.props.containerId, {
141
+      name: 'navigation.playground.BackHandlerScreen'
142
+    });
143
+  }
144
+
137 145
   onClickPushOrientationMenuScreen() {
138 146
     Navigation.push(this.props.containerId, {
139 147
       name: 'navigation.playground.OrientationSelectScreen'

+ 2
- 0
playground/src/containers/index.js 파일 보기

@@ -9,6 +9,7 @@ const OrientationSelectScreen = require('./OrientationSelectScreen');
9 9
 const OrientationDetectScreen = require('./OrientationDetectScreen');
10 10
 const ScrollViewScreen = require('./ScrollViewScreen');
11 11
 const CustomDialog = require('./CustomDialog');
12
+const BandHandlerScreen = require('./BackHandlerScreen');
12 13
 
13 14
 function registerContainers() {
14 15
   Navigation.registerContainer(`navigation.playground.ScrollViewScreen`, () => ScrollViewScreen);
@@ -21,6 +22,7 @@ function registerContainers() {
21 22
   Navigation.registerContainer(`navigation.playground.OrientationSelectScreen`, () => OrientationSelectScreen);
22 23
   Navigation.registerContainer(`navigation.playground.OrientationDetectScreen`, () => OrientationDetectScreen);
23 24
   Navigation.registerContainer('navigation.playground.CustomDialog', () => CustomDialog);
25
+  Navigation.registerContainer('navigation.playground.BackHandlerScreen', () => BandHandlerScreen);
24 26
 }
25 27
 
26 28
 module.exports = {