Aplikacje mobilne często używają więcej niż jednego ekranu, aby odpowiednio zaprezentować dane. W jaki sposób możemy stworzyć więcej niż jeden ekran? Do tego właśnie służy StackNavigator.
Aby móc używać nawigacji pomiędzy ekranami, musisz w folderze ze swoim projektem zainstalować bibliotekę o nazwie react-navigation. Możesz to zrobić wpisując kolejno polecenia:
npm install --save react-navigation
npm install --save react-native-gesture-handler
react-native link react-native-gesture-handler
Zajrzyj również do dokumentacji: react-navigation – getting started
Nasz kod zaczniemy od zmodyfikowania podstawowego komponentu: App.js
App.js:
import React, {Component} from 'react';
import StackNavigator from './components/StackNavigator';
export default class App extends Component {
render() {
return <StackNavigator />
}
}
Następnie utworzymy folder o nazwie components, a w nim komponent StackNavigator.js , w którym zaimportujemy funkcję createStackNavigator – aby utworzyć nasz navigator oraz funkcję createAppContainer – aby nawigator zamknąć w kompnencie, który będziemy mogli wyeksportować. Utworzymy również komponenty o nazwach Screen1.js , Screen2.js , Screen3.js które zaimportujemy do StackNavigatora.
StackNavigator.js
import React, {Component, PureComponent} from 'react';
import { createStackNavigator, createAppContainer } from "react-navigation";
import Screen1 from './Screen1';
import Screen2 from './Screen2';
import Screen3 from './Screen3';
Teraz utworzymy zmienną o nazwie MyStackNavigator , która będzie naszym navigatorem. Wewnątrz nawigatora dodamy trzy ekrany – ekran główny: Screen1, oraz dwa ekrany poboczne: Screen2 i Screen3.
const MyStackNavigator = createStackNavigator(
{
Home: Screen1,
Screen2: Screen2,
Screen3: Screen3,
},
{
initialRouteName: 'Home',
defaultNavigationOptions: {
headerStyle: { height: 55, backgroundColor: 'orange' },
headerTitleStyle: { fontWeight: 'bold', color: '#fff },
},
}
);
InitialRouteName – to screen, który będzie się ładował jako domyślny. Poniżej ustawiamy również kilka opcji dla nagłówka: wysokość, kolor tła, odcień elementów znajdujących się w nagłówku, kolor i wagę czcionki.
Na koniec tworzymy komponent ze StackNavigatora, abyśmy mogli podłączyć go do naszej aplikacji:
const AppContainer = createAppContainer(MyStackNavigator);
export default class StackNavigator extends React.Component {
render() {
return <AppContainer />;
}
}
Teraz uzupełnimy komponent Screen1, by wyświetlić dane na ekranie. Umieścimy w nim przycisk, który kierował będzie do kolejnego ekranu i dodamy odpowiednie style.
Screen1.js:
import React, {Component} from 'react';
import {StyleSheet, Text, View, TouchableHighlight } from 'react-native';
export default class Screen1 extends Component {
static navigationOptions = {
title: 'Home',
};
render() {
return (
<View style={styles.container}>
<Text style={styles.text}> This is Screen 1</Text>
<TouchableHighlight onPress={() => this.props.navigation.navigate('Screen2')} style={styles.touchableHighlight} underlayColor={'#f1f1f1'}>
<Text style={styles.text}>Go to Screen 2</Text>
</TouchableHighlight>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
backgroundColor: 'yellow',
alignItems: 'center',
justifyContent: 'center',
},
text: {
fontSize: 20,
fontWeight: 'bold',
margin: 20,
},
touchableHighlight: {
backgroundColor: 'white',
marginVertical: 10,
alignSelf: 'stretch',
alignItems: 'center',
}
})
W navigationOptions ustawiamy tytuł ekranu, który będzie wyświetlał się w nagłówku. W komponencie zwracamy przycisk w postaci TouchableHighlight , który możemy odpowiednio wystylować. Po naciśnięciu przycisku nawigacja przekieruje nas do ekranu numer 2. Odpowiedzialny jest za to kod onPress={() => this.props.navigation.navigate('Screen2')}
Kolejne ekrany wyglądają następująco:
Screen2.js:
import React, {Component} from 'react';
import {StyleSheet, Text, View, TouchableHighlight } from 'react-native';
export default class Screen1 extends Component {
static navigationOptions = {
title: 'Screen 2',
};
render() {
return (
<View style={styles.container}>
<Text style={styles.text}> This is Screen 2</Text>
<TouchableHighlight onPress={() => this.props.navigation.navigate('Screen3')} style={styles.touchableHighlight} underlayColor={'#f1f1f1'}>
<Text style={styles.text}>Go to Screen 3</Text>
</TouchableHighlight>
<TouchableHighlight onPress={() => this.props.navigation.goBack()} style={styles.touchableHighlight} underlayColor={'#f1f1f1'}>
<Text style={styles.text}>Go back to Screen 1</Text>
</TouchableHighlight>
</View>
)
}
}
Screen3.js:
import React, {Component} from 'react';
import {StyleSheet, Text, View, TouchableHighlight } from 'react-native';
export default class Screen1 extends Component {
static navigationOptions = {
title: 'Screen 3',
};
render() {
return (
<View style={styles.container}>
<Text style={styles.text}> This is Screen 3</Text>
<TouchableHighlight onPress={() => this.props.navigation.popToTop()} style={styles.touchableHighlight} underlayColor={'#f1f1f1'}>
<Text style={styles.text}>Go to Screen 1</Text>
</TouchableHighlight>
<TouchableHighlight onPress={() => this.props.navigation.goBack()} style={styles.touchableHighlight} underlayColor={'#f1f1f1'}>
<Text style={styles.text}>Go back to Screen 2</Text>
</TouchableHighlight>
</View>
)
}
}
Ekran 2 i 3 zawierają po dwa przyciski, jeden prowadzi do kolejnego (lub pierwszego) ekranu, a drugi do poprzedniego. Ustawiając im właściwość underlayColor możemy zmienić kolor przycisku po jego dotknięciu.
<br>
Całość prezentuje się następująco:
Wszystko działa jak należy, ale możemy jeszcze poprawić efekt przewijania. W zmiennej MyStackNavigator dodamy właściwość transitionConfig, która sprawi, że nasz ekran będzie się wysuwał z prawej strony:
const MyStackNavigator = createStackNavigator(
{
Home: {screen: Screen1},
Screen2: Screen2,
Screen3: Screen3,
},
{
initialRouteName: 'Home',
defaultNavigationOptions: {
headerStyle: { height: 55, backgroundColor: 'orange' },
headerTitleStyle: { fontWeight: 'bold', color: '#fff' },
},
transitionConfig: () => ({
transitionSpec: {
duration: 500,
},
screenInterpolator: sceneProps => {
const { position, layout, scene } = sceneProps
const index = scene.index
const width = layout.initWidth
const slideFromRight = {
opacity: position.interpolate({
inputRange: [ index, index + 1],
outputRange: [1, 1],
}),
transform: [{
translateX: position.interpolate({
inputRange: [index - 1, index, index + 1],
outputRange: [width, 0, -20],
})
}] }
return slideFromRight
},
}),
}
);
Teraz efekt jest lepszy: