Example
Below example shows a full example how to extend ThemeProvider and implement setColorScheme
method to support to dark mode
and using multiple themes.
To support multipe themes you must extend ThemeProvider
and implement onChangeTheme
method or you can create you own ThemeContext.
- colors
- MyThemeProvider
- ThemeSettings
- App
/src/theme/colors.ts
import { ColorValue } from 'react-native';
import { light, BaseTheme } from '@flexnative/theme-context';
export interface MyColorsColors {
color1: ColorValue,
color2: ColorValue
};
export const lightRedTheme: BaseTheme<MyColorsColors> = {
...light,
primary: '#FF0000',
color1: '#C51162',
color2: '#7B1FA2',
}
export const lightBlueTheme: BaseTheme<MyColorsColors> = {
...light,
primary: '#00008B',
color1: '#C51162',
color2: '#7B1FA2',
}
export const darkRedTheme: BaseTheme<MyColorsColors> = {
...dark,
primary: '#FF0000',
color1: '#C51162',
color2: '#7B1FA2',
}
export const darkBlueTheme: BaseTheme<MyColorsColors> = {
...dark,
primary: '#00008B',
color1: '#C51162',
color2: '#7B1FA2',
}
/src/theme/MyThemeProvider.tsx
import React from 'react';
import { ColorSchemeName, Appearance } from 'react-native';
import { ThemeProvider } from '@flexnative/theme-context';
import { MyColorsColors } from './colors';
export default class MyThemeProvider extends ThemeProvider<MyColorsColors> {
// Here you can implement your logic to get inital theme
// if you are storing your theme in persistent memory (db or local storage).
async onLoad(): Promise<void> {
const appThemeStorage = await Storage.getItem(APP_THEME, defaultTheme);
Appearance.addChangeListener(this.onAppearanceChange);
this.setState({
colorScheme: appThemeStorage.colorScheme,
colors: getThemeColors(appThemeStorage.primaryColor, appThemeStorage.colorScheme)
});
}
onAppearanceChange = (colorScheme: Appearance.AppearancePreferences) => {
if(this.state.colorScheme === null) {
this.setState({ ...this.state });
}
else {
this.setState({
colorScheme: colorScheme.colorScheme,
colors: getThemeColors(this.state.colors.primary, colorScheme.colorScheme)
});
}
}
onChangeTheme = async (theme: BaseTheme): Promise<void> => {
await Storage.saveItem(APP_THEME, { colorScheme: this.state.colorScheme, primaryColor: theme.primary });
this.setState({ colors: theme });
}
onChangeColorSchemeTheme = async (colorScheme: ColorSchemeName): Promise<void> => {
await Storage.saveItem(APP_THEME, { colorScheme: colorScheme, primaryColor: this.state.colors.primary });
this.setState({
colorScheme: colorScheme ?? Appearance.getColorScheme(),
colors: getThemeColors(this.state.colors.primary, colorScheme)
});
}
}
/src/screens/ThemeSettings.tsx
import React from 'react';
import { StyleSheet, Pressable, View, Text, ColorValue } from 'react-native';
import { useThemeContext } from '@flexnative/theme-context';
import { lightRedTheme, lightBlueTheme, darkRedTheme, darkBlueTheme, MyColorsColors } from './colors';
type BtnToggleProps = {
title: string,
backgroundColor: ColorValue,
theme: 'red' | 'blue'
}
const BtnColorToggle = React.memo((props: BtnToggleProps) => {
const theme = useThemeContext();
const onTheme = async (): Promise<void> => {
let newColors: BaseTheme<MyColorsColors>;
if(theme.colorScheme === 'dark')
newColors = props.theme 'red' ? darkRedTheme : darkBlueTheme;
else
newColors = props.theme 'red' ? lightRedTheme : lightBlueTheme;
await theme.setTheme!(props.theme);
};
return (
<Pressable onPress={onTheme} style={[styles.btn, {backgroundColor: props.backgroundColor}]}>
<Text style={styles.btnTitle}>
{props.title}
</Text>
</Pressable>
);
});
export default React.memo(() => {
const theme = useThemeContext();
return (
<View style={[styles.container, {backgroundColor: theme.colors.primary}]}>
<Text style={styles.title}>Theme Settings</Text>
<BtnColorToggle title='Set Red Theme' backgroundColor='#FF0000' theme={redTheme} />
<BtnColorToggle title='Set Blue Theme' backgroundColor='#00008B' theme={blueTheme} />
</View>
);
});
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 15
},
title: {
fontSize: 32,
fontWeight: 'bold',
paddingVertical: 18,
color: '#ffffff'
},
btn: {
width: '100%',
borderStyle: 'solid',
borderWidth: 1,
paddingVertical: 15,
alignItems: 'center',
justifyContent: 'center',
marginVertical: 15
},
btnTitle: {
fontSize: 18,
color: '#ffffff'
},
});
/App.ts
import React from 'react';
import ThemeSettings from './src/screens/ThemeSettings.tsx';
import MyThemeProvider from './src/theme/MyThemeProvider.tsx';
export default function App() {
return (
<MyThemeProvider>
<ThemeSettings />
</MyThemeProvider>
);
}