Kurs React Native · Moduł 2: Listy i style
StatusBar i Theming
W tej lekcji2
Kontroluj wygląd status bara i stwórz system motywów dla aplikacji.
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' }]}>
Status Bar Demo
</Text>
<Pressable
style={[styles.button, { backgroundColor: isDark ? '#2980b9' : '#3498db' }]}
onPress={() => setIsDark(!isDark)}
>
<Text style={styles.buttonText}>
Przełącz na {isDark ? 'jasny' : 'ciemny'} motyw
</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',
},
});System motywów z 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="Skarb Atlantydy"
description="Legendarny klejnot z głębin oceanu"
/>
<ThemedCard
title="Trójząb Posejdona"
description="Broń władcy mórz"
/>
<Pressable
style={[styles.button, { backgroundColor: theme.colors.primary }]}
onPress={toggleTheme}
>
<Text style={styles.buttonText}>
{theme.dark ? 'Jasny motyw' : 'Ciemny motyw'}
</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',
},
});Gratulacje! Opanowałeś/aś zaawansowane komponenty i stylowanie w React Native!
Kod do tej lekcji: 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: wybierz motyw na podstawie stanu isDark.
// const theme = isDark ? darkTheme : lightTheme;
const theme = darkTheme;
// TODO: stwórz funkcję toggleTheme, która odwraca isDark.
// const toggleTheme = () => setIsDark(!isDark);
const toggleTheme = () => {};
// TODO: przekaż { theme, toggleTheme } do propsa value Providera.
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 }]}>Skarb Atlantydy</Text>
</View>
<Pressable style={styles.button} onPress={toggleTheme}>
<Text style={styles.buttonText}>
{theme.dark ? 'Jasny motyw' : 'Ciemny motyw'}
</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',
},
});Hasła z dokumentacji w tej lekcji
Widzisz błąd w tej lekcji?
Sprawdź się
Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.
1. Która wartość barStyle StatusBar pokazuje jasne ikony (dla ciemnego tła)?
2. Co zwraca hook useColorScheme()?
Zadania praktyczne w grze
- Układanie w pionie
Uporządkuj kroki tworzenia systemu motywów z Context API:
- Edytor kodu
Uzupełnij kod ThemeProvider i ThemeContext.