I have included a snack expo here that reproduces the exact layout of my project. App.js -> stack of screens. I am trying to figure out the best way to toggle between light theme and dark theme. I do not care for the ios dark theme setting to trigger this, for now, I just want the button to trigger it.
I would like there to be a button displayed on my home screen that when pushed toggles to the theme it is not currently on. I originally wanted to use theme provider to set my colors for each theme and then call that color on each page rather than the hard coded color but have failed to do so.
When you have a stack of screens being called in a tab navigator, what is the best way to use a dark theme?
You need to use the theme prop of the NavigationContainer
but your are still responsible for providing the styling for each of your components.
That said, there are a couple of things we need to do here.
theme
prop of the NavigationContainer
.We can solve the first problem by wrapping the NavigationContainer
into a ContextProvider
as follows.
import React, {useState} from 'react';
import {
DefaultTheme,
DarkTheme,
NavigationContainer,
} from '@react-navigation/native';
export const ThemeContext = React.createContext();
export default function App() {
const [theme, setTheme] = useState(DefaultTheme)
return (
<ThemeContext.Provider value={{theme, setTheme}}>
<NavigationContainer theme={theme}>
</NavigationContainer>
</ThemeContext.Provider>
);
}
In your Toggle
component you can then change the theme dynamically as follows.
import {ThemeContext} from '../App'
import {
DefaultTheme,
DarkTheme,
} from '@react-navigation/native';
const Toggle = (props) => {
const { setTheme, theme } = React.useContext(ThemeContext);
return (
<TouchableOpacity onPress={() => setTheme(theme === DefaultTheme ? DarkTheme : DefaultTheme)}>
</TouchableOpacity>
);
}
You will notice that changing the theme will not change anything in your current setup. This is because you need to take care of this yourself.
This could be done using either the context again or the useTheme
hook. For your HomeScreen
this could be done as follows.
import { useTheme } from '@react-navigation/native';
const Home = () => {
const { colors } = useTheme();
return (
<View style={{justifyContent: 'center', alignItems: 'center', flex: 1, backgroundColor: colors.background}}>
<Toggle/>
<Screen/>
</View>
);
}
Toggling the button changes the theme
now. You can access the default theme colors
using the useTheme
hook but you still need to apply it to your components. You could also provide a custom theme which is done similar.