React Native のダークモードの切り替え
「React Native」のダークモードの切り替え方法をまとめました。
前回
1. Stack のダークモードの切り替え
(1) サンプルアプリの準備。
「React Native の React Nativation の使い方」の「Stack の使い方」のサンプルにダークモードの切り替えを追加します。
(2) コードの編集。
・theme.ts
テーマごとの色を定義します。
const lightTheme = {
headerColor: '#fff',
backgroundColor: '#f2f2f2',
textColor: '#000',
buttonColor: '#2396f1',
drawerColor: '#fff',
};
const darkTheme = {
headerColor: '#333',
backgroundColor: '#1c1c1c',
textColor: '#fff',
buttonColor: '#2396f1',
drawerColor: '#333',
};
export const themes = {
light: lightTheme,
dark: darkTheme,
};
・App.tsx
useColorScheme()でシステムのテーマ設定 (ダーク or ライト) を取得し、それを元にNavigationContainerにテーマを指定します。
import React from 'react';
import { useColorScheme } from 'react-native';
import { NavigationContainer, DefaultTheme, DarkTheme } from '@react-navigation/native';
import Main from './Main';
// アプリ
function App() {
const theme = useColorScheme();
// UI
return (
<NavigationContainer theme={theme === 'dark' ? DarkTheme : DefaultTheme}>
<Main/>
</NavigationContainer>
);
}
export default App;
・Main/index.tsx
useColorScheme()でシステムのテーマ設定を取得し、それに応じてコンポーネントに色を指定します。
import React from 'react';
import { useColorScheme } from 'react-native';
import { createStackNavigator, CardStyleInterpolators } from '@react-navigation/stack';
import HomeScreen from './home';
import DetailScreen from './detail';
import { themes } from '../theme';
// Stackの準備
const Stack = createStackNavigator();
// Mainの画面構成
function Main() {
const theme = useColorScheme();
if (theme == null) return;
return (
<>
<Stack.Navigator
initialRouteName="Home"
screenOptions={{
cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
headerStyle: {
backgroundColor: themes[theme].headerColor,
},
headerTintColor: themes[theme].textColor,
}}
>
<Stack.Screen name="Home画面" component={HomeScreen} />
<Stack.Screen name="Detail画面" component={DetailScreen} />
</Stack.Navigator>
</>
);
}
export default Main;
・Main/home.tsx
import { View, Text, Button, useColorScheme } from 'react-native';
import { themes } from '../theme';
// Home画面
// @ts-ignore
function HomeScreen({ navigation }) {
const theme = useColorScheme();
if (theme == null) return;
return (
<View style={{
flex: 1, alignItems: 'center', justifyContent: 'center',
backgroundColor: themes[theme].backgroundColor
}}>
<Text style={{ color: themes[theme].textColor }}>Home画面</Text>
<Button
color={themes[theme].buttonColor}
title='Detail画面に遷移'
onPress={() => navigation.navigate('Detail画面')}
/>
</View>
);
}
export default HomeScreen;
・Main/detail.tsx
import { View, Text, Button, useColorScheme } from 'react-native';
import { themes } from '../theme';
// Detail画面
// @ts-ignore
function DetailScreen({ navigation }) {
const theme = useColorScheme();
if (theme == null) return;
return (
<View style={{
flex: 1, alignItems: 'center', justifyContent: 'center',
backgroundColor: themes[theme].backgroundColor
}}>
<Text style={{ color: themes[theme].textColor }}>Detail画面</Text>
<Button
color={themes[theme].buttonColor}
title='Home画面に戻る'
onPress={() => navigation.goBack()}
/>
</View>
);
}
export default DetailScreen;
(3) コードの実行。
ダークモード、ライトモードが切り替わることを確認します。
npm start
2. Drawer のダークモードの切り替え
(1) サンプルアプリの準備。
「React Native の React Nativation の使い方」の「Drawer の使い方」のサンプルにダークモードの切り替えを追加します。
(2) コードの編集。
・Main/index.tsx
import React from 'react';
import { useColorScheme } from 'react-native';
import { createDrawerNavigator } from '@react-navigation/drawer';
import HomeScreen from './home';
import DetailScreen from './detail';
import SettingScreen from './setting';
import { themes } from '../theme';
// Drawerの準備
const Drawer = createDrawerNavigator();
// Mainの画面構成
function Main() {
const theme = useColorScheme();
if (theme == null) return;
return (
<>
<Drawer.Navigator
initialRouteName="Home"
screenOptions={{
headerStyle: {
backgroundColor: themes[theme].headerColor,
},
headerTintColor: themes[theme].textColor,
drawerStyle: {
backgroundColor: themes[theme].drawerColor,
},
drawerLabelStyle: {
color: themes[theme].textColor,
},
}}
>
<Drawer.Screen name="Home画面" component={HomeScreen} />
<Drawer.Screen name="Detail画面" component={DetailScreen} />
<Drawer.Screen name="Setting画面" component={SettingScreen} />
</Drawer.Navigator>
</>
);
}
export default Main;
・Main/home.tsx
import { View, Text, useColorScheme } from 'react-native';
import { themes } from '../theme';
// Home画面
// @ts-ignore
function HomeScreen({ navigation }) {
const theme = useColorScheme();
if (theme == null) return;
return (
<View style={{
flex: 1, alignItems: 'center', justifyContent: 'center',
backgroundColor: themes[theme].backgroundColor
}}>
<Text style={{ color: themes[theme].textColor }}>Home画面</Text>
</View>
);
}
export default HomeScreen;
・Main/detail.tsx
import { View, Text, useColorScheme } from 'react-native';
import { themes } from '../theme';
// Detail画面
// @ts-ignore
function DetailScreen({ navigation }) {
const theme = useColorScheme();
if (theme == null) return;
return (
<View style={{
flex: 1, alignItems: 'center', justifyContent: 'center',
backgroundColor: themes[theme].backgroundColor
}}>
<Text style={{ color: themes[theme].textColor }}>Detail画面</Text>
</View>
);
}
export default DetailScreen;
・Main/setting.tsx
import { View, Text, useColorScheme } from 'react-native';
import { themes } from '../theme';
// Setting画面
// @ts-ignore
function DetailScreen({ navigation }) {
const theme = useColorScheme();
if (theme == null) return;
return (
<View style={{
flex: 1, alignItems: 'center', justifyContent: 'center',
backgroundColor: themes[theme].backgroundColor
}}>
<Text style={{ color: themes[theme].textColor }}>Setting画面</Text>
</View>
);
}
export default DetailScreen;
(3) コードの実行。
ダークモード、ライトモードが切り替わることを確認します。
npm start
3. BottomTab のダークモードの切り替え
(1) サンプルアプリの準備。
「React Native の React Nativation の使い方」の「BottomTab の使い方」のサンプルにダークモードの切り替えを追加します。
(2) コードの編集。
・Main/index.tsx
import React from 'react';
import { useColorScheme } from 'react-native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import Icon from 'react-native-vector-icons/Ionicons';
import HomeScreen from './home';
import DetailScreen from './detail';
import SettingScreen from './setting';
import { themes } from '../theme';
// Tabの準備
const Tab = createBottomTabNavigator();
// Mainの画面構成
function Main() {
const theme = useColorScheme();
if (theme == null) return;
return (
<>
<Tab.Navigator
initialRouteName="Home"
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
const icons: any = {
'Home画面': 'home',
'Detail画面': 'notifications',
'Setting画面': 'albums'
};
const iconName = `${icons[route.name]}${focused ? '' : '-outline'}`;
return <Icon name={iconName} size={size} color={color} />;
},
headerStyle: {
backgroundColor: themes[theme].headerColor,
},
headerTintColor: themes[theme].textColor,
})}
>
<Tab.Screen name="Home画面" component={HomeScreen} />
<Tab.Screen name="Detail画面" component={DetailScreen} />
<Tab.Screen name="Setting画面" component={SettingScreen} />
</Tab.Navigator>
</>
);
}
export default Main;
・Main/home.tsx
import { View, Text, useColorScheme } from 'react-native';
import { themes } from '../theme';
// Home画面
// @ts-ignore
function HomeScreen({ navigation }) {
const theme = useColorScheme();
if (theme == null) return;
return (
<View style={{
flex: 1, alignItems: 'center', justifyContent: 'center',
backgroundColor: themes[theme].backgroundColor
}}>
<Text style={{ color: themes[theme].textColor }}>Home画面</Text>
</View>
);
}
export default HomeScreen;
・Main/detail.tsx
import { View, Text, useColorScheme } from 'react-native';
import { themes } from '../theme';
// Detail画面
// @ts-ignore
function DetailScreen({ navigation }) {
const theme = useColorScheme();
if (theme == null) return;
return (
<View style={{
flex: 1, alignItems: 'center', justifyContent: 'center',
backgroundColor: themes[theme].backgroundColor
}}>
<Text style={{ color: themes[theme].textColor }}>Detail画面</Text>
</View>
);
}
export default DetailScreen;
・Main/setting.tsx
import { View, Text, useColorScheme } from 'react-native';
import { themes } from '../theme';
// Setting画面
// @ts-ignore
function DetailScreen({ navigation }) {
const theme = useColorScheme();
if (theme == null) return;
return (
<View style={{
flex: 1, alignItems: 'center', justifyContent: 'center',
backgroundColor: themes[theme].backgroundColor
}}>
<Text style={{ color: themes[theme].textColor }}>Setting画面</Text>
</View>
);
}
export default DetailScreen;
(3) コードの実行。
ダークモード、ライトモードが切り替わることを確認します。
npm start