Was bisher geschah?
Es wird eine Navigation und zusätzliche Bildschirmseiten mit den Einstellungen, der Hauptseite, Info und einem leeren Dummy-Screen erstellt. Die “Welcome to React“-Seite bleibt als Home-Screen bestehen. In dem Header wird links eine Menü- und rechts eine Einstellungen-Schaltfläche eingefügt, die jeweils eine Seitenleiste mit Auswahl-Optionen einblenden. In der Mitte soll der Titel der aktiven Seite angezeigt werden.
Screen Properties Objekt-Typ
Die src/types/default.ts-Datei wird mit dem DefaultScreenProps-Typ erweitert. Der Typ erbt von DefaultProps und enthält die Navigations-Parameter für die einzelnen Seiten.
src/types/default.ts
import React from 'react';
import { NavigationParams, NavigationScreenProp, NavigationState } from 'react-navigation';
export interface DefaultProps {
children?: React.ReactNode;
}
export interface DefaultScreenProps extends DefaultProps{
navigation: NavigationScreenProp<NavigationState, NavigationParams>;
}
Der Screen-Header enthält den Titel der aktiven Seite und die Menü- und Einstellungen-Schaltflächen.
Einen neuen Ordner src/components mit der Datei Header.tsx erstellen.
src/components/Header.tsx
import React from 'react';
import {
Body, Button, Header as NativeHeader, Icon, Left, Right, Text, Title,
} from 'native-base';
import { StyleSheet, Alert } from 'react-native';
import { DefaultScreenProps } from '../types/default';
import { DrawerActions } from 'react-navigation-drawer';
interface HeaderProps extends DefaultScreenProps{
title: string;
}
const Header = (props: HeaderProps): React.FunctionComponentElement<HeaderProps> => {
const onClickMenuButton = (): void => {
props.navigation.navigate({routeName: 'Menu', action: DrawerActions.toggleDrawer()});
};
const onClickMoreButton = (): void => {
props.navigation.navigate({routeName: 'More', action: DrawerActions.toggleDrawer()});
};
return (
<NativeHeader>
<Left style={styles.iconWrapper}>
<Button transparent onPress={onClickMenuButton}>
<Icon name="menu" />
</Button>
</Left>
<Body>
<Title>
<Text style={styles.headerText}>{props.title}</Text>
</Title>
</Body>
<Right style={styles.iconWrapper}>
<Button transparent onPress={onClickMoreButton}>
<Icon name="more" />
</Button>
</Right>
</NativeHeader>
);
};
const styles = StyleSheet.create({
iconWrapper: {
flexDirection: 'row',
alignItems: 'center',
},
headerText: {
fontSize: 22,
fontWeight: 'bold',
textAlign: 'center',
color: 'white',
width: 200,
flexDirection: 'row',
flexWrap: 'nowrap'
}
});
export default Header;
Eingesetzt wird hier die Header-Komponente aus dem NativeBase-Paket. Sie hat drei Bereiche. Links(<Left />) für die Menü-Schaltfläche, Mitte (<Body />) für den Titel und rechts (<Right />) für die Einstellungen-Schaltfläche. Der Titel wird aus den JSON-Übersetzungsdateien geholt. Die Schaltflächen lösen Ereignisse aus, die links bzw. rechts eine Sidebar mit den Auswahl-Optionen einblenden.
Screens erstellen
Es werden vier Screens erstellt. Home für die “Welcome to React”-Seite, Settings für die Einstellungen, About für die App-Informationen und Dummy als Vorlage für die weitere Screen-Implementierungen.
Zuerst einen neuen Ordner src/screens mit vier Dateien: Home.tsx, Settings.tsx, About.tsx und Dummy.tsx erstellen.
Home
Diese Seite enthält eine modifizierte Kopie der “Welcome to React” – Hauptseite aus App.tsx.
src/screens/Home.tsx
import React from 'react';
import { StyleSheet } from 'react-native';
import { Container, Content, Form, Label } from 'native-base';
import { useTranslation } from 'react-i18next';
import Header from '../components/Header';
import {
Header as ReactHeader,
LearnMoreLinks,
Colors,
DebugInstructions,
ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';
import { DefaultScreenProps } from '../types/default';
console.disableYellowBox = true;
const Home = (props: DefaultScreenProps): React.FunctionComponentElement<DefaultScreenProps> =>{
const { t, i18n } = useTranslation();
return (
<Container>
<Header navigation={props.navigation} title={t('home.headerTitle')} />
<Content>
<ReactHeader />
<Form style={styles.body}>
<Label style={styles.sectionContainer}>
<Label style={styles.sectionTitle}>Step One</Label>
<Label style={styles.sectionDescription}>
Edit <Label style={styles.highlight}>App.tsx</Label> to change
this screen and then come back to see your edits.
</Label>
</Label>
<Form style={styles.sectionContainer}>
<Label style={styles.sectionTitle}>See Your Changes</Label>
<Label style={styles.sectionDescription}>
<ReloadInstructions />
</Label>
</Form>
<Form style={styles.sectionContainer}>
<Label style={styles.sectionTitle}>Debug</Label>
<Label style={styles.sectionDescription}>
<DebugInstructions />
</Label>
</Form>
<Form style={styles.sectionContainer}>
<Label style={styles.sectionTitle}>Learn More</Label>
<Label style={styles.sectionDescription}>
Read the docs to discover what to do next:
</Label>
</Form>
<LearnMoreLinks />
</Form>
</Content>
</Container>
);
};
const styles = StyleSheet.create({
body: {
backgroundColor: Colors.white,
},
sectionContainer: {
marginTop: 32,
paddingHorizontal: 24,
},
sectionTitle: {
fontSize: 24,
fontWeight: '600',
color: Colors.black,
},
sectionDescription: {
marginTop: 8,
fontSize: 18,
fontWeight: '400',
color: Colors.dark,
},
highlight: {
fontWeight: '700',
},
});
export default Home;
Settings
Das Einstellungen-Bildschirm enthält eine Auswahl der Sprache und die Passworteingabe.
src/screens/Settings.tsx
import React from 'react';
import {
Button, Container, Content, Form, Text, Item, Picker, Icon, Label, Input,
} from 'native-base';
import { useTranslation } from 'react-i18next';
import { StyleSheet, Alert } from 'react-native';
import { useDispatch, useSelector } from 'react-redux';
import Header from '../components/Header';
import { DefaultScreenProps } from '../types/default';
import { AppState } from '../reducers/appReducer';
import { setSelectedLanguage, SetPassword } from '../actions/appActions';
const Settings = (props: DefaultScreenProps): React.FunctionComponentElement<DefaultScreenProps> => {
const { t, i18n } = useTranslation();
const dispatch = useDispatch();
const selectedLanguage = useSelector((state: { app: AppState}) => state.app.selectedLanguage);
const password = useSelector((state: { app: AppState}) => state.app.password);
const onChangePassword = (newPassword: string): void => {
dispatch(SetPassword(newPassword));
};
const savePassword = () => {
Alert.alert(t('settings.savePassword'));
};
const onSelectedLanguageChange = (newSelectedLanguage: string): void => {
i18n.changeLanguage(newSelectedLanguage).then((value) => {
dispatch(setSelectedLanguage(newSelectedLanguage));
});
};
return (
<Container>
<Header navigation={props.navigation} title={t('settings.headerTitle')} />
<Content>
<Form>
<Item picker style={styles.settingsPickerItem}>
<Label>
{t('settings.language')}:{' '}
</Label>
<Picker
mode="dropdown"
iosIcon={<Icon name="arrow-down" />}
style={{ width: undefined }}
iosHeader={t('settings.selectLanguage')}
placeholder={t('settings.selectLanguage')}
placeholderStyle={{ color: '#bfc6ea' }}
placeholderIconColor="#007aff"
selectedValue={selectedLanguage}
onValueChange={onSelectedLanguageChange}
>
<Picker.Item label={t('settings.languages.german')} value="de" />
<Picker.Item label={t('settings.languages.english')} value="en" />
</Picker>
</Item>
<Item picker style={styles.settingsPickerItem}>
<Label>
{t('settings.password')}:{' '}
</Label>
<Input
value={password}
onChangeText={onChangePassword}
secureTextEntry
onEndEditing={savePassword}
/>
</Item>
<Button style={styles.saveButton}>
<Text>{t('general.save')}</Text>
</Button>
</Form>
</Content>
</Container>
);
};
const styles = StyleSheet.create({
saveButton: {
margin: 8,
justifyContent: 'center',
},
settingsPickerItem: {
marginLeft: 8,
},
});
export default Settings;
Dummy
Dummy ist eine leere Vorlage für spätere Implementierungen. Sie enthält als Platzhalter nur einen Text und einen Link.
src/screens/Dummy.tsx
import React from 'react';
import {
Container, Content, Form, Text,
} from 'native-base';
import { useTranslation } from 'react-i18next';
import { StyleSheet, Linking } from 'react-native';
import Header from '../components/Header';
import { DefaultScreenProps } from '../types/default';
const Dummy = (props: DefaultScreenProps): React.FunctionComponentElement<DefaultScreenProps> => {
const { t, i18n } = useTranslation();
return (
<Container>
<Header navigation={props.navigation} title={t('dummy.headerTitle')} />
<Content>
<Form>
<Text style={styles.text}>{t('dummy.text')}</Text>
<Text>Link:
<Text style={styles.link}
onPress={() => Linking.openURL('http://www.technik-tipps-und-tricks.de')}>
Technik Tipps und Tricks
</Text>
</Text>
</Form>
</Content>
</Container>
);
};
const styles = StyleSheet.create({
text: {
color: 'red',
},
link: {
color: "#1B95E0",
textDecorationLine: "underline",
fontWeight: "bold"
},
});
export default Dummy;
About
Die Info-Seite wird später die App-Informationen anzeigen, wie die Version, den Anbieter, ein Icon usw.
src/screens/About.tsx
import React from 'react';
import {
Container, Content, Form, Text,
} from 'native-base';
import { useTranslation } from 'react-i18next';
import { StyleSheet } from 'react-native';
import Header from '../components/Header';
import { DefaultScreenProps } from '../types/default';
const About = (props: DefaultScreenProps): React.FunctionComponentElement<DefaultScreenProps> => {
const { t, i18n } = useTranslation();
return (
<Container>
<Header navigation={props.navigation} title={t('about.headerTitle')} />
<Content>
<Form>
<Text style={styles.text}>{t('about.text')}</Text>
</Form>
</Content>
</Container>
);
};
const styles = StyleSheet.create({
text: {
color: 'red',
},
link: {
color: "#1B95E0",
textDecorationLine: "underline",
fontWeight: "bold"
},
});
export default About;
Internationalisierung ergänzen
Die Internationalisierungsdateien mit der Übersetzung ergänzen.
src/translations/en.json
{
"general": {
"loading": "Load...",
"save": "Save",
"messages": {
"someMessage": "Some Message"
},
"errors": {
"unknown": "Unknown error occurred!"
}
},
"profile": {
"headerTitle": "Personal Data",
"fields": {
"firstName": "first name",
"lastName": "family name",
"phoneNumber": "phone number",
"emailAddress": "email Address"
}
},
"home": {
"headerTitle": "Home"
},
"settings": {
"headerTitle": "Settings",
"selectLanguage": "Select the Language",
"language": "Language",
"languages": {
"german": "German",
"english": "English"
},
"password": "Password",
"savePassword": "Password successfully changed"
},
"dummy": {
"headerTitle": "Dummy",
"text": "Empty Dummy Page."
},
"about": {
"headerTitle": "About",
"text": "Empty Info Page."
}
}
src/translations/de.json
{
"general": {
"loading": "Laden...",
"save": "Speichern",
"messages": {
"someMessage": "Irgendeine Nachricht"
},
"errors": {
"unknown": "Unbekannter Fehler aufgetreten!"
}
},
"profile": {
"headerTitle": "Persönliche Daten",
"fields": {
"firstName": "Vorname",
"lastName": "Familienname",
"phoneNumber": "Telefonnummer",
"emailAddress": "E-Mail-Adresse"
}
},
"home": {
"headerTitle": "Start"
},
"settings": {
"headerTitle": "Einstellungen",
"selectLanguage": "Wähle die Sprache",
"language": "Sprache",
"languages": {
"german": "Deutsch",
"english": "Englisch"
},
"password": "Passwort",
"savePassword": "Passwort erfolgreich geändert"
},
"dummy": {
"headerTitle": "Dummy",
"text": "Leere Dummy Seite."
},
"about": {
"headerTitle": "Info",
"text": "Leere Info Seite."
}
}
Die linke und rechte Optionsleiste mit den Einträgen sollen je nach Klick auf das Menü- oder Mehr-Icon im Header eingeblendet werden.
Eine neue Datei src/components/MenuSidebar.tsx erstellen.
src/components/MenuSidebar.tsx
import React from 'react';
import {
Body, Container, Content, Icon, Left, ListItem, Right, Text,
} from 'native-base';
import { FlatList } from 'react-native';
import { useTranslation } from 'react-i18next';
import { DefaultScreenProps } from '../types/default';
const MenuSidebar = (props: DefaultScreenProps): React.FunctionComponentElement<DefaultScreenProps> => {
const { navigation } = props;
const { t } = useTranslation();
const routes = [{
route: 'Home',
text: t('home.headerTitle'),
icon: 'home',
iconColor: 'red',
}, {
route: 'Dummy',
text: t('dummy.headerTitle'),
icon: 'account',
iconColor: '#FF9501',
}];
return (
<Container>
<Content>
<FlatList
data={routes}
keyExtractor={(item) => item.route}
renderItem={({ item }): React.FunctionComponentElement<DefaultScreenProps> => (
<ListItem
icon
key={item.route}
onPress={(): void => {
navigation.navigate(item.route);
navigation.closeDrawer();
}}
>
<Left>
<Icon
active
name={item.icon}
type="MaterialCommunityIcons"
/>
</Left>
<Body>
<Text>{item.text}</Text>
</Body>
<Right />
</ListItem>
)}
/>
</Content>
</Container>
);
};
export default MenuSidebar;
Eine neue Datei src/components/MoreSidebar.tsx erstellen.
src/components/MoreSidebar.tsx
import React from 'react';
import {
Body, Container, Content, Icon, Left, ListItem, Right, Text,
} from 'native-base';
import { FlatList } from 'react-native';
import { useTranslation } from 'react-i18next';
import { DefaultScreenProps } from '../types/default';
const MoreSidebar = (props: DefaultScreenProps): React.FunctionComponentElement<DefaultScreenProps> => {
const { navigation } = props;
const { t } = useTranslation();
const routes = [{
route: 'Settings',
text: t('settings.headerTitle'),
icon: 'settings',
iconColor: '#FF9501',
}, {
route: 'About',
text: t('about.headerTitle'),
icon: 'information-outline',
iconColor: '#FF9501',
}];
return (
<Container>
<Content>
<FlatList
data={routes}
keyExtractor={(item) => item.route}
renderItem={({ item }): React.FunctionComponentElement<DefaultScreenProps> => (
<ListItem
icon
key={item.route}
onPress={(): void => {
navigation.navigate(item.route);
navigation.closeDrawer();
}}
>
<Left>
<Icon
active
name={item.icon}
type="MaterialCommunityIcons"
/>
</Left>
<Body>
<Text>{item.text}</Text>
</Body>
<Right />
</ListItem>
)}
/>
</Content>
</Container>
);
};
export default MoreSidebar;
AppContainer (Router) erstellen
Der AppContainer oder Router kapselt die Seitennavigation. Je eine DrawerNavigator-Komponente für die linke und rechte Seitenleiste werden erstellt und in einem SwitchNavigator zusammengefasst. Aus diesem wird der AppContainer gebildet.
Zuerst wird das DrawerNavigator-Paket installiert:
$ npm install react-navigation-drawer
Die Datei src/AppContainer.tsx erstellen.
src/AppContainer.tsx
import React from 'react';
import { createAppContainer, createSwitchNavigator } from 'react-navigation';
import { createDrawerNavigator } from 'react-navigation-drawer';
import MenuSidebar from './components/MenuSidebar';
import MoreSidebar from './components/MoreSidebar';
import Home from './screens/Home';
import Dummy from './screens/Dummy';
import Settings from './screens/Settings';
import About from './screens/About';
const MoreNavigator = createDrawerNavigator(
{
Settings: { screen: Settings },
About: { screen: About }
},
{
contentComponent: (props) => <MoreSidebar {...props} />,
drawerPosition: 'right',
drawerType: 'slide',
}
);
const MenuNavigator = createDrawerNavigator(
{
Home: { screen: Home },
Dummy: { screen: Dummy },
},
{
contentComponent: (props) => <MenuSidebar {...props} />,
drawerPosition: 'left',
drawerType: 'slide',
}
);
const RootNavigator = createSwitchNavigator(
{
Menu: { screen: MenuNavigator },
More: { screen: MoreNavigator },
}
);
const Router = createAppContainer(RootNavigator);
export default Router;
Router einbinden
Die App-Hautdatei App.tsx mit folgendem Inhalt ersetzen.
App.tsx
import React from 'react';
import { Provider } from 'react-redux';
import { PersistGate } from 'redux-persist/integration/react';
import { Root } from 'native-base';
import configureStore from './src/configureStore';
import { DefaultProps } from './src/types/default';
import Router from './src/AppContainer';
import I18nGate from './src/i18nGate';
const { store, persistor } = configureStore();
const App = (): React.FunctionComponentElement<DefaultProps> => {
return (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<I18nGate>
<Root>
<Router />
</Root>
</I18nGate>
</PersistGate>
</Provider>
);
};
export default App;
Die Provider– und PersistGate-Komponenten stellen den permanenten Redux-Speicher zur Verfügung. I18Gate dient der Internationalisierung, Root ist der App-Hauptcontainer und Router die Navigation mit den Screens.
Die fertige Navigation
![001-Navigation-Screens [Image]](http://www.technik-tipps-und-tricks.de/wp-content/uploads/2020/01/001-Navigation-Screens.png)
![002-Navigation-Screens [Image]](http://www.technik-tipps-und-tricks.de/wp-content/uploads/2020/01/002-Navigation-Screens.png)
![003-Navigation-Screens [Image]](http://www.technik-tipps-und-tricks.de/wp-content/uploads/2020/01/003-Navigation-Screens.png)
![004-Navigation-Screens [Image]](http://www.technik-tipps-und-tricks.de/wp-content/uploads/2020/01/004-Navigation-Screens.png)
Wie geht es weiter?
War diese Seite für dich informativ? Hat sie dir gefallen und geholfen?
Dann unterstütze die Weiterentwicklung mit einer kleinen Spende!
Die Spenden werden für die Lizenzen sowie neue Hard- und Software verwendet, die für weitere Projekte auf dieser Webseite eingesetzt werden.