見出し画像

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

次回



いいなと思ったら応援しよう!