Cours React Native · Module 2: Listes et styles
StatusBar et gestion des thèmes
Dans cette leçon2
Contrôle l'apparence de la barre d'état et crée un système de thèmes pour ton application.
StatusBar
import { SafeAreaView, View, Text, StyleSheet, StatusBar, Pressable } from 'react-native';
import { useState } from 'react';
export default function StatusBarExample() {
const [isDark, setIsDark] = useState(true);
return (
<SafeAreaView style={[
styles.container,
{ backgroundColor: isDark ? '#1a5276' : '#ecf0f1' }
]}>
<StatusBar
barStyle={isDark ? 'light-content' : 'dark-content'}
backgroundColor={isDark ? '#1a5276' : '#ecf0f1'}
animated={true}
/>
<View style={styles.content}>
<Text style={[styles.title, { color: isDark ? '#fff' : '#2c3e50' }]}>
Démo de la barre d'état
</Text>
<Pressable
style={[styles.button, { backgroundColor: isDark ? '#2980b9' : '#3498db' }]}
onPress={() => setIsDark(!isDark)}
>
<Text style={styles.buttonText}>
Passer au thème {isDark ? 'clair' : 'sombre'}
</Text>
</Pressable>
</View>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
content: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
},
title: {
fontSize: 24,
fontWeight: 'bold',
marginBottom: 30,
},
button: {
paddingVertical: 14,
paddingHorizontal: 24,
borderRadius: 8,
},
buttonText: {
color: '#fff',
fontSize: 16,
fontWeight: '600',
},
});Système de thèmes avec Context
// context/ThemeContext.tsx
import { createContext, useContext, useState, ReactNode } from 'react';
interface Theme {
dark: boolean;
colors: {
background: string;
card: string;
text: string;
textSecondary: string;
primary: string;
border: string;
};
}
const lightTheme: Theme = {
dark: false,
colors: {
background: '#f5f6fa',
card: '#ffffff',
text: '#2c3e50',
textSecondary: '#7f8c8d',
primary: '#3498db',
border: '#dcdde1',
},
};
const darkTheme: Theme = {
dark: true,
colors: {
background: '#1a5276',
card: '#2c3e50',
text: '#ffffff',
textSecondary: '#bdc3c7',
primary: '#3498db',
border: '#34495e',
},
};
interface ThemeContextType {
theme: Theme;
toggleTheme: () => void;
}
const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
export function ThemeProvider({ children }: { children: ReactNode }) {
const [isDark, setIsDark] = useState(true);
const theme = isDark ? darkTheme : lightTheme;
const toggleTheme = () => setIsDark(!isDark);
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
export function useTheme() {
const context = useContext(ThemeContext);
if (!context) {
throw new Error('useTheme must be used within ThemeProvider');
}
return context;
}// components/ThemedCard.tsx
import { View, Text, StyleSheet } from 'react-native';
import { useTheme } from '../context/ThemeContext';
interface ThemedCardProps {
title: string;
description: string;
}
export default function ThemedCard({ title, description }: ThemedCardProps) {
const { theme } = useTheme();
return (
<View style={[styles.card, { backgroundColor: theme.colors.card }]}>
<Text style={[styles.title, { color: theme.colors.text }]}>
{title}
</Text>
<Text style={[styles.description, { color: theme.colors.textSecondary }]}>
{description}
</Text>
</View>
);
}
const styles = StyleSheet.create({
card: {
padding: 16,
borderRadius: 12,
marginBottom: 12,
},
title: {
fontSize: 18,
fontWeight: '600',
marginBottom: 4,
},
description: {
fontSize: 14,
},
});// App.tsx
import { SafeAreaView, View, StyleSheet, StatusBar, Pressable, Text } from 'react-native';
import { ThemeProvider, useTheme } from './context/ThemeContext';
import ThemedCard from './components/ThemedCard';
function HomeScreen() {
const { theme, toggleTheme } = useTheme();
return (
<SafeAreaView style={[styles.container, { backgroundColor: theme.colors.background }]}>
<StatusBar barStyle={theme.dark ? 'light-content' : 'dark-content'} />
<View style={styles.content}>
<ThemedCard
title="Trésor de l'Atlantide"
description="Un joyau légendaire des profondeurs de l'océan"
/>
<ThemedCard
title="Trident de Poséidon"
description="Arme du souverain des mers"
/>
<Pressable
style={[styles.button, { backgroundColor: theme.colors.primary }]}
onPress={toggleTheme}
>
<Text style={styles.buttonText}>
{theme.dark ? 'Thème clair' : 'Thème sombre'}
</Text>
</Pressable>
</View>
</SafeAreaView>
);
}
export default function App() {
return (
<ThemeProvider>
<HomeScreen />
</ThemeProvider>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
content: {
flex: 1,
padding: 20,
},
button: {
marginTop: 20,
paddingVertical: 14,
borderRadius: 8,
alignItems: 'center',
},
buttonText: {
color: '#fff',
fontSize: 16,
fontWeight: '600',
},
});Félicitations ! Tu as maîtrisé les composants avancés et le stylage dans React Native !
Code de cette leçon : App.tsx
import React, { createContext, useContext, useState, ReactNode } from 'react';
import { SafeAreaView, View, Text, Pressable, StyleSheet } from 'react-native';
const lightTheme = {
dark: false,
background: '#f5f6fa',
card: '#ffffff',
text: '#2c3e50',
};
const darkTheme = {
dark: true,
background: '#1a5276',
card: '#2c3e50',
text: '#ffffff',
};
const ThemeContext = createContext({ theme: darkTheme, toggleTheme: () => {} });
function ThemeProvider({ children }: { children: ReactNode }) {
const [isDark, setIsDark] = useState(true);
// TODO : choisis le thème en fonction de l'état isDark.
// const theme = isDark ? darkTheme : lightTheme;
const theme = darkTheme;
// TODO : crée une fonction toggleTheme qui inverse isDark.
// const toggleTheme = () => setIsDark(!isDark);
const toggleTheme = () => {};
// TODO : transmets { theme, toggleTheme } à la prop value du Provider.
return (
<ThemeContext.Provider value={{ theme: darkTheme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
function HomeScreen() {
const { theme, toggleTheme } = useContext(ThemeContext);
return (
<SafeAreaView style={[styles.container, { backgroundColor: theme.background }]}>
<View style={[styles.card, { backgroundColor: theme.card }]}>
<Text style={[styles.text, { color: theme.text }]}>Trésor de l'Atlantide</Text>
</View>
<Pressable style={styles.button} onPress={toggleTheme}>
<Text style={styles.buttonText}>
{theme.dark ? 'Thème clair' : 'Thème sombre'}
</Text>
</Pressable>
</SafeAreaView>
);
}
export default function App() {
return (
<ThemeProvider>
<HomeScreen />
</ThemeProvider>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
card: {
padding: 16,
borderRadius: 12,
marginBottom: 20,
},
text: {
fontSize: 18,
fontWeight: '600',
},
button: {
paddingVertical: 14,
borderRadius: 8,
alignItems: 'center',
backgroundColor: '#3498db',
},
buttonText: {
color: '#fff',
fontSize: 16,
fontWeight: '600',
},
});Entrées de la documentation utilisées dans cette leçon
Tu as repéré une erreur dans cette leçon ?
Teste tes connaissances
Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.
1. Quelle valeur de barStyle de la StatusBar affiche des icônes claires (pour un fond sombre) ?
2. Que renvoie le hook useColorScheme() ?
Tâches pratiques dans le jeu
- Tri vertical
Ordonne les étapes de création d'un système de thèmes avec Context API :
- Éditeur de code
Complète le code de ThemeProvider et ThemeContext.