تم ها مختلف در ری اکت نیتیو - React Native Multi Theme

در این نوشته قصد داریم در مورد نحوه ایجاد تم های مختلف مثل light و dark در ری اکت نیتیو به صورت عملی صبحت کنیم. همونطور که میدونید هر دو سیستم عامل Android و IOS قابلیت تغییر تم بین حالت دارک و لایت رو دارا هستن، در نتیجه کاربران معمولا انتظار دارن که این قابلیت از سمت اپلیکیشن هایی که ما توسعه میدیم وجود داشته باشه. برای افزودن این قابلیت بهتره که تا آخر این مقاله با من همراه باشید.خلاصه کاری که قراره انجام بدیم رو میتونید تو تصویر پایین ببیند و به کد اون تو این ریپازیتوری گیت هاب دسترسی داشته باشید.خروجی نهاییپیش نیاز هااول از همه یه پروژه ری اکت نیتیو با دستور زیر ایجاد میکنیم:npx react-native init rn_themingگام بعدی پکیج react-navigation رو از طریق دستورالعمل های خودش نصب کنید. برای ذخیره حالت دارک یا لایت برای استفاده های بعدی اپلیکیشن هم از پکیج react-native-community/async-storage استفاده میکنیمساختار پروژهتو این مرحله ساختار پروژه رو عوض میکنیم. من خودم معمولا از چنین ساختاری تو پروژه هام استفاده میکنم:-src - components برای قرار دادن کامپوننت های پروژه - TabBar.js - StatusBar.js - navigation - index.js برای تعریف کردن صفحات - screens صفحات مختلف پروژه - Home.js صفحه اصلی - Setting.js صفحه تنظیمات - providers - themeProvider.js برای هوک های مربوط به تغییر تم - theme.json نگه داری مقادیر تم های مختلف App.js index.js فایل اصلی و اولیه پروژهبعد از اینکه ساختار رو عوض کنیم یه ادیتی تو فایل index.js میزنیم و ایمپورت فایل App رو تو اون عوض میکنیم:import App from './App'; to ----> import App from './src/App';بخش Navigationبرای Navigation پروژه یه bottom tab navigator ایجاد میکنیم که داخل اون دو تب یکی برای home و دیگری برای setting باشه. tabBar مربوط به اون رو هم از کامپوننت TabBar که خودمون تو کامپوننت ها ساختیم استفاده میکنیم.import React from 'react'; import {NavigationContainer} from '@react-navigation/native'; import {createBottomTabNavigator} from '@react-navigation/bottom-tabs'; import HomeScreen from './../screens/Home'; import SettingScreen from './../screens/Setting'; import MyTabBar from './../components/TabBar' const Tab = createBottomTabNavigator(); export default function MainNavigation() { return ( <NavigationContainer> <Tab.Navigator tabBar={props => <MyTabBar {...props} />}> <Tab.Screen name=&quotHome&quot component={HomeScreen} /> <Tab.Screen name=&quotSettings&quot component={SettingScreen} /> </Tab.Navigator> </NavigationContainer> ); }تم های مختلف پروژهاول رنگای مختلفی که میخایم تو مد دارک و لایت استفاده کنیم رو با کلیدهای دلخواه به فرمت جیسون در میاریم و تو فایل themes.json میریزیم:{{ &quotlight&quot: { &quotprimaryText&quot: &quot#0b132b&quot, &quotbackgroundColor&quot: &quot#eff7f6&quot, &quottabBarBackgroundColor&quot: &quot#e6ebe0&quot, &quottabBarActiveColor&quot: &quot#02c39a&quot }, &quotdark&quot: { &quotprimaryText&quot: &quot#98c1d9&quot, &quotbackgroundColor&quot: &quot#14213d&quot, &quottabBarBackgroundColor&quot: &quot#2b2d42&quot, &quottabBarActiveColor&quot: &quot#fcbf49&quot }}هوک های مربوط به تغییر تمحالا میریم سراغ فایل themeProvider که لاجیک اصلی تغییر تم رو تو اون قرار بدیم:در ابتدا پکیج ها و کامپوننت های لازم رو ایمپورت میکنیم و متغیرهای ثابت مورد نیاز برای کل فایل رو تعریف میکنیم:providers/themeProvider.js import React, { useContext, useState, useEffect } from 'react';import AsyncStorage from '@react-native-community/async-storage';import THEMES from './themes.json';const STORAGE_KEY = 'THEME_ID'; کلید مربوطه به ذخیره وضعیت تم در حافظه برای استفاده های بعدیconst ThemeContext = React.createContext();در ادامه فایل themeProvider یک context به نام ThemeContextProvider میسازیم و یک state به نام themeID تو اون تعریف می کنیم که این state رو در بقیه کامپوننت ها به اشتراک بزاره. providers/themeProvider.js export const ThemeContextProvider = ({ children }) => {const [themeID, setThemeID] = useState();useEffect(() => {(async () => {const storedThemeID = await AsyncStorage.getItem(STORAGE_KEY);if (storedThemeID) {setThemeID(storedThemeID);} else {setThemeID('light');}})();}, []);return (<ThemeContext.Provider value={{ themeID, setThemeID }}>{!!themeID ? children : null}</ThemeContext.Provider>);};حالا برای استفاده از این context باید فایل App.js را به شکل زیر ویرایش کنیم:App.js import React from 'react';import {View, Text} from 'react-native';import MainNavigation from './navigation'import { ThemeContextProvider } from './providers/themeProvider';function App() {return ( <ThemeContextProvider> <MainNavigation /> </ThemeContextProvider> );}export default App;تو این فایل کل navigation اپلیکیشنمون رو درون ThemeContextProvider قرار میدیم. دیگه حالا تو همه کامپوننت هامون به themeID و setThemeID دسترسی داریم و میتونیم مقادیر themeID رو استفاده یا عوض کنیم.هنوز کارمون تموم نشده. بیاید با توجه به مفهموم HOC یه تغیری دیگه تو فایل themeProvider بدیم. در انتهای این فایل یه تابع دیگه به اسم withTheme اضافه میکنیم. کار این تابع اینه که یه Component رندر میکنه که مقادیر تم فعلی مثه لایت یا دارک رو در اختیار هر کامپوننتی که ازش استفاده کنه قرار میدهexport function withTheme(Component) {return props => { function changeTheme (id) {emeID } = useContext(ThemeContext);function changeTheme (id) { // تابعی که تم رو تغییر میده براساس اون چیزی که از ورودی میگیرهAsyncStorage.setItem(STORAGE_KEY, id);setThemeID(id)}const getTheme = themeID => THEMES[themeID]; // تابعی که تم فعلی رو برمیگردونهconst switchTheme = () => { // تابعی که تم رو سوئیچ میکنه بین لایت و دارکconst newTheme = themeID === 'light' ? 'dark' : 'light'; changeTheme(newTheme)};const setTheme = (key) => { تابعی برای تغییر تم changeTheme(newTheme))};return (<Component{...props}themes={THEMES}theme={getTheme(themeID)}themeID={themeID}setTheme={setTheme}switchTheme={switchTheme} این بخش توابعی و متغیرهای مورد نیاز برای مدیریت تم رو در اختیار کامپوننت های قرار میده که از withTheme استفاده می کنند/>);};}تعریف کامپوننت هاحالا که کارمون با themeContext تموم شد کامپوننت های مختلف رو به شکل زیر تعریف می کنیم:components -> TabBar.js import React from 'react';import {BottomTabBar} from '@react-navigation/bottom-tabs';import { withTheme } from './../providers/themeProvider';const MyTabBar = props => {return (<BottomTabBar{...props}activeTintColor={props.theme.tabBarActiveColor}inactiveTintColor={props.theme.primaryText}style={{backgroundColor: props.theme.tabBarBackgroundColor, fontWeight: 'bold'}}/>);};export default withTheme(MyTabBar); components -> StatusBar.js import React from 'react';import {StatusBar} from 'react-native';import { withTheme } from './../providers/themeProvider';function MyStatusBar({themeID}) {const oppositeTheme = themeID === 'light' ? 'dark' : 'light'return (<StatusBar barStyle ={oppositeTheme + '-content'} hidden = {false} backgroundColor = &quot#00BCD4&quot translucent = {true}/>);};export default withTheme(MyStatusBar);screens -> Home.js import * as React from 'react';import {Text, View, StyleSheet} from 'react-native';import { withTheme } from './../providers/themeProvider';import MyStatusBar from './../components/StatusBar';function HomeScreen({theme}) {return (<View style={{...styles.container, backgroundColor: theme.backgroundColor}}><MyStatusBar /><Text style={{...styles.text, color: theme.primaryText}}>Welcome to change React Native Theme Changer Sample APP</Text></View>);}const styles = StyleSheet.create({container: {flex: 1, justifyContent: 'center', alignItems: 'center'},text: {fontSize: 24,fontWeight: 'bold',textAlign: 'center'}})export default withTheme(HomeScreen);صفحه setting که عملیات تغییر تم تو اون اتفاق میفته هم به شکل زیر خواهد بود:screens -> Setting.js import * as React from 'react';import {Text, View, StyleSheet, TouchableOpacity} from 'react-native';import { withTheme } from './../providers/themeProvider';import MyStatusBar from './../components/StatusBar';function SettingsScreen({theme, setTheme, switchTheme, themeID}) {return (<View style={{...styles.container, backgroundColor: theme.backgroundColor}}><MyStatusBar /><TouchableOpacity style={styles.button} onPress={() => switchTheme()}><Text style={{...styles.text, color: theme.primaryText}}>Switch Theme</Text></TouchableOpacity>{themeID === 'light' && <TouchableOpacity style={styles.button} onPress={() => setTheme('dark')}><Text style={{...styles.text, color: theme.primaryText}}>Change To Dark</Text></TouchableOpacity> }{themeID === 'dark' && <TouchableOpacity style={styles.button} onPress={() => setTheme('light')}><Text style={{...styles.text, color: theme.primaryText}}>Change to light</Text></TouchableOpacity>}</View>);}const styles = StyleSheet.create({container: {flex: 1,justifyContent: 'center',alignItems: 'center',},button: {borderWidth: 1,borderRadius: 8,borderColor: 'grey',padding: 10,margin: 20},text: {fontSize: 20,fontWeight: 'bold'}})export default withTheme(SettingsScreen); جمع بندیدر این مقاله اومدیم یه نمونه پروژه از نحوه ایجاد تم های مختلف مثل dark و light رو در React Native پیاده سازی کردیم. می تونید سورس کد پروژه رو اینجا ببینید.