Cours React Native · Module 2: Listes et styles

StatusBar et gestion des thèmes

3 min de lecture ·
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. 1. Quelle valeur de barStyle de la StatusBar affiche des icônes claires (pour un fond sombre) ?

  2. 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.

Articles utiles