Appearance
De header en de footer
Inhoud
De header opzetten
In tegenstelling tot andere mobiele frameworks heeft React Native geen specifiek header component. In plaats daarvan wordt de header aangeleverd als onderdeel van de routing configuratie. Als je de app hebt gestart, zal je zien dat er nu standaard een header verschijnt met de naam van de route als titel.
Je kan dit in standaard situaties gebruiken, maar wij gaan onze header zelf configureren.
Het Header component
Take The Wheel
Implementeer nu het onderstaande in de app.
Maak in de projectmap een nieuwe map components aan en maak in deze map een bestand aan met de naam Header.tsx
Exporteer binnen het component een functie en geef een props variabele mee als argument. Deze props variabele gaan we gebruiken om de titel aanpasbaar te maken.
Libraries importeren
Importeer de volgende libraries in het Header component:
- React vanuit 'react'
- StyleSheet, Text, View en Image vanuit 'react-native'
Het logo
Laad een logo naar keuze op in de assets map.
Maak in het Header component een nieuwe constante logo aan en initialiseer deze constante met de require methode.
De template
Binnen de return van de functie gaan we de template definiëren.
- Maak een View component aan.
- Maak binnen het View component een Image component aan. Geef het logo mee als waarde van het source attribuut.
- Maak binnen het View component een nieuw View component aan. Binnen dit View component voorzie je een Text component. De inhoud van dit Text component is props.headerTitle waarmee de titel dynamisch gaan kunnen tonen.
Stijlen definiëren
- Maak onder de functie een nieuwe constante styles aan.
- Maak een selector header en voeg hieraan volgende eigenschappen toe:
- width: '100%'
- height: 70,
- alignItems: 'center'
- justifyContent: 'center'
- Pas deze stijl toe op het eerste View component
- Maak een selector image en voeg hieraan volgende eigenschappen toe:
- width: 35
- height: 35
- Pas deze stijl toe op het Image component
- Maak een selector text en voeg hieraan volgende eigenschappen toe:
- fontFamily: 'Poppins'
- Pas deze stijl toe op het Text component
- Maak een selector header en voeg hieraan volgende eigenschappen toe:
Uitgewerkte Code
tsx
import React from "react";
import { StyleSheet, Text, View, Image } from "react-native";
const logo = require('../assets/logo.png');
export default function Header(props: any) {
return (
<View style={styles.header}>
<Image style={styles.image} source={logo}/>
<View>
<Text style={styles.text}>{props.headerTitle}</Text>
</View>
</View>
)
}
const styles = StyleSheet.create({
header: {
width: '100%',
height: 70,
alignItems: 'center',
justifyContent: 'center'
},
image: {
width: 35,
height: 35,
},
text: {
fontFamily: 'Poppins'
}
})Een Font toevoegen
Net zoals in andere toepassingen, kan je in React Native ook custom lettertypes gebruiken. In de app gaan we het lettertype Poppins gebruiken. We gaan ook inbouwen dat de applicatie niet kan geladen worden als het lettertype niet kan ingeladen worden.
Take The Wheel
Implementeer nu het onderstaande in de app.
Download het Poppins lettertype, maak in de assets map een nieuwe fonts map aan en laad hier het Poppins-Regular.ttf bestand in op.
Installeer de volgende libraries (met npx expo install):
- expo-font: maakt het laden van lettertypen tijdens runtime en het gebruik ervan in React Native-componenten mogelijk.
- expo-splash-screen: wordt gebruikt om aan te geven dat het splash-screen (loading screen) zichtbaar moet blijven totdat expliciet wordt aangegeven dat het moet worden verborgen. Dit is handig om taken te doen die achter de schermen gebeuren, zoals API-calls, lettertypen vooraf laden, het splash-screen animeren enzovoort.
Aangezien het font gaat gebruikt worden, gaan we het in het App component inladen. Gebruik de documentatie van expo-font om het lettertype op een juiste manier in te laden.
Uitgewerkte Code
tsx
import 'react-native-gesture-handler';
import React, {useEffect} from 'react';
import * as Font from 'expo-font';
import * as SplashScreen from 'expo-splash-screen';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import HomePage from './app/Home';
const Stack = createStackNavigator();
export default function App() {
const [fontsLoaded, error] = Font.useFonts({
'OpenSans': require('./assets/fonts/Poppins-Regular.ttf'),
})
useEffect(() => {
if (fontsLoaded || error) {
SplashScreen.hideAsync();
}
}, [fontsLoaded, error]);
if (!fontsLoaded && !error) {
return null;
}
return (
<NavigationContainer>
<Stack.Navigator
initialRouteName="General News"
>
<Stack.Screen
name="General News"
component={HomePage}
/>
</Stack.Navigator>
</NavigationContainer>
);
}useEffect
Als het lettertype op een juiste manier hebt ingeladen, zal je gezien hebben dat je useEffect van React hebt moeten inladen.
useEffect is één van de vele hooks die je kan gebruiken in React (Native). Een hook kan je beschouwen als een speciale functie die je kan gebruiken in componenten om toegang te krijgen tot React functies zoals de state of lifecycle methoden. Doorheen de cursus gaan we verschillende hooks behandelen en useEffect is er eentje van.
Met useEffect kan je dingen beheren die buiten het standaard gedrag van je component vallen, zoals bijvoorbeeld ophalen van data, een service aanspreken, een timer instellen, .... Of kan je acties uitvoeren wanneer een component wordt gemount, geüpdatet of ge-unmount.
useEffect heeft een callback-functie en een array als argumenten. In de callback-functie ga je schrijven wat er moet gebeuren. In de array geef je aan welke variabelen moeten gevolgd worden. Laat je die leeg dan wordt de functie enkel uitgevoerd bij de eerste render. In ons geval zal de functie uitgevoerd worden wanneer het font niet bestaat.
De Header inladen
Take The Wheel
Implementeer nu het onderstaande in de app.
In het App component voeg je aan het Stack.Screen component nu ook een options attribuut toe. Aan dit attribuut geef je de header eigenschap mee als object. Deze eigenschap verwacht een callbackfunctie waarbij we het Header component inladen. Opgelet, vergeet de titel niet mee te geven.
Als je het resultaat nu bekijkt, kan het zijn dat de header niet goed gepositioneerd staat. Om dit op te lossen gaan we het volgende doen:
- Geef aan het Stack.Navigator component het screenOptions attribuut mee. Dit attribuut krijgt een object met de volgende eigenschappen als waarde:
- headerMode: 'screen': dat aangeeft hoe de header moet gerendered worden.
- Laad SafeAreaView en StatusBar in vanuit 'react-native'.
- SafeAreaView past automatisch opvulling toe om het deel van de applicatie weer te geven dat niet wordt bedekt door navigatiebalken, tabbalken, werkbalken en andere weergaven.
- Met StatusBar kan je de statusbalk van de app beheren.
Voeg een SafeAreaView toe aan het App component en voeg in dit component
- Een StatusBar component toe
- De andere, eerder aangemaakte, componenten
Maak onder de functie een nieuwe constante styles aan.
- Maak een selector container en voeg hieraan volgende eigenschap toe:
- flex: 1 Voeg deze container nu toe aan het SafeAreaView component. (Enkel de flex eigenschap dient momenteel nog in de container selector te staan)
Uitgewerkte Code
tsx
import 'react-native-gesture-handler';
import React, {useEffect} from 'react';
import { SafeAreaView, StyleSheet, StatusBar } from 'react-native';
import * as Font from 'expo-font';
import * as SplashScreen from 'expo-splash-screen';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import HomePage from './app/Home';
const Stack = createStackNavigator();
export default function App() {
const [fontsLoaded, error] = Font.useFonts({
'OpenSans': require('./assets/fonts/Poppins-Regular.ttf'),
})
useEffect(() => {
if (fontsLoaded || error) {
SplashScreen.hideAsync();
}
}, [fontsLoaded, error]);
if (!fontsLoaded && !error) {
return null;
}
return (
<SafeAreaView style={styles.container}>
<StatusBar/>
<NavigationContainer>
<Stack.Navigator
initialRouteName="General News"
screenOptions={{
headerMode:'screen',
}}
>
<Stack.Screen
name="General News"
component={HomePage}
options={{
header: () => <Header headerTitle="General News"/>
}}
/>
</Stack.Navigator>
</NavigationContainer>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
});De footer opzetten
In de footer gaan we de links naar de verschillende secties van onze app onderbrengen. We kunnen de footer niet toevoegen als geen scherm aan de navigation stack. de belangrijkste reden hiervoor is dat een footer een vaste positie heeft en zich meestal onderaan het scherm bevindt. Schermen in een stack navigator wisselen echter volledig uit, waardoor de footer zou verdwijnen en opnieuw verschijnen bij elke navigatie.
Dit brengt met zich mee dat de footer geen automatische toegang heeft tot de navigatie. Een mogelijke oplossing is om de navigatie manueel op te halen in het component.
De RootNavigation
Take The Wheel
Implementeer het onderstaande om de footer toe te voegen aan de app.
Om dit op te lossen gaan we een helper bestand aanmaken. Maak in de de projectmap een nieuwe map helpers aan. Maak in deze map het bestand RootNavigation.tsx aan. Hierin mag je de volgende code onderbrengen:
tsx
import * as React from 'react';
import { NavigationContainerRef } from '@react-navigation/native';
type Routes = {
'General News': String;
'About': String;
};
export const navigationRef = React.createRef<NavigationContainerRef<Routes>>();
export function navigate(name: keyof Routes) {
navigationRef.current?.navigate(name);
}We gaan hierin een eigen navigate functie definiëren waarbij we telkens de route doorgeven waarnaar er moet genavigeerd worden. Deze functie gaan we gebruiken in de footer.
De type Routes gaan we eventueel uitbreiden met andere routes.
Het footer component
Maakt in de components map een bestand aan met de naam Footer.tsx en exporteer binnen het component een functie.
Libraries importeren
Importeer de volgende libraries in het Header component:
- React vanuit 'react'
- StyleSheet, Text, View en Pressable vanuit 'react-native'
- De navigate functie vanuit het RootNavigation bestand.
De template
Binnen de return van de functie gaan we de template definiëren.
- Maak een View component aan.
- Maak binnen het View component een Pressable component aan. Dit is een manier om het principe van een knop te gebruiken in React Native.
- Maak binnen het Pressable component een Text component aan. De inhoud van dit Text component is de naam van de route naar waar je wil navigeren. Bijvoorbeeld 'Home'.
Maak nu ook een Pressable component aan voor de 'About' en de 'Quote' pagina.
Stijlen definiëren
- Maak onder de functie een nieuwe constante styles aan.
- Maak een selector footer en voeg hieraan volgende eigenschappen toe:
- width: '100%'
- height: 80,
- flexDirection: 'row'
- alignItems: 'flex-start'
- justifyContent: 'center' Pas deze stijl toe op het View component
- Maak een selector button en voeg hieraan volgende eigenschappen toe:
- padding: 20 Pas deze stijl toe op het Pressable component
- Maak een selector footer en voeg hieraan volgende eigenschappen toe:
Uitgewerkte Code
tsx
import React from "react";
import { StyleSheet, Text, View, Pressable } from "react-native";
import { navigate } from '../helpers/RootNavigation';
export default function Footer() {
return (
<View style={styles.footer}>
<Pressable
style={styles.button}
onPress={() => navigate('General News')}
>
<Text>Home</Text>
</Pressable>
<Pressable style={styles.button}>
<Text>About</Text>
</Pressable>
<Pressable style={styles.button}>
<Text>Quote</Text>
</Pressable>
</View>
)
}
const styles = StyleSheet.create({
footer: {
width: '100%',
height: 80,
flexDirection: 'row',
alignItems: 'flex-start',
justifyContent: 'center'
},
button: {
padding: 20
}
})De Footer inladen
Importeer het Footer component nu in het App component en laadt het in onder het NavigationContainer component.
Om te kunnen testen of het navigeren tussen de tabs in de footer werkt, maak je het About component aan en voeg je het nodige toe aan het Stack Navigator component om dit werkende te krijgen.