React Native Context 实现APP的主题开发

重口难调,如果APP的主色调可以自定义,一定程度上就解决了这个问题。

实现思路 

  1. 每个组件之间共享同一个color变量,当用户自定义主题颜色的时候,所有的页面主色调一起发生变化。并且把用户设置的颜色保存到本地存储之中。
  2. APP每次启动的时候,从本地存储中获取主题的颜色信息。

效果如下:

js/context/ThemeContext.js

/* eslint-disable prettier/prettier */
import React, {useState,useEffect, createContext} from 'react';
import AsyncStorage from '@react-native-community/async-storage';

export const ThemeContext = createContext();

export const ThemeProvider = props => {
    const [backgroundColor,setBackgroundColor] = useState('#1677ff');   //#1677ff
    useEffect(()=>{
        const queryThemeConfig = async () => {
            try {
                const cacheBackgroundColor = await AsyncStorage.getItem('@backgroundColor');
                if(cacheBackgroundColor!=null){
                    setBackgroundColor(cacheBackgroundColor);
                }
            } catch (e) {
                // saving error
            }
        };
        queryThemeConfig().then(r => void(0) );
    },[]);
    return (
        <ThemeContext.Provider value={[backgroundColor,setBackgroundColor]}>
            {props.children}
        </ThemeContext.Provider>
    );
};

js/screen/SettingsScreen.js

/* eslint-disable prettier/prettier */
import React, { useState,useContext } from "react";
import { FlatList, SafeAreaView, StatusBar, StyleSheet, Text, TouchableOpacity } from "react-native";
import {ThemeContext} from '../context/ThemeContext';
import AsyncStorage from '@react-native-community/async-storage';
const themeData = [
    {
        text: 'Default',
        color: '#1677ff',
    },
    {
        text: 'Red',
        color: '#F44336',
    },
    {
        text: 'Pink',
        color: '#E91E63',
    },
    {
        text: 'Purple',
        color: '#9C27B0',
    },
    {
        text: 'DeepPurple',
        color: '#673AB7',
    },
    {
        text: 'Indigo',
        color: '#3F51B5',
    },
    {
        text: 'Blue',
        color: '#2196F3',
    },
    {
        text: 'LightBlue',
        color: '#03A9F4',
    },
    {
        text: 'Cyan',
        color: '#00BCD4',
    },
    {
        text: 'Teal',
        color: '#009688',
    },
    {
        text: 'Green',
        color: '#4CAF50',
    },
    {
        text: 'LightGreen',
        color: '#8BC34A',
    },
    {
        text: 'Lime',
        color: '#CDDC39',
    },
    {
        text: 'Yellow',
        color: '#FFEB3B',
    },
    {
        text: 'Amber',
        color: '#FFC107',
    },
    {
        text: 'Orange',
        color: '#FF9800',
    },
    {
        text: 'DeepOrange',
        color: '#FF5722',
    },
    {
        text: 'Brown',
        color: '#795548',
    },
    {
        text: 'Grey',
        color: '#9E9E9E',
    },
    {
        text: 'BlueGrey',
        color: '#607D8B',
    },
    {
        text: 'Black',
        color: '#000000',
    }
];

const Item = ({ item, onPress, style }) => (
    <TouchableOpacity onPress={onPress} style={[styles.item, style]}>
        <Text style={styles.title}>{item.text}</Text>
    </TouchableOpacity>
);

const SettingScreen = () => {
    const [backgroundColor,setBackgroundColor] = useContext(ThemeContext);
    const saveThemeConfig = async (color) => {
        try {
            await AsyncStorage.setItem('@backgroundColor', color);
        } catch (e) {
            // saving error
        }
    };

    const renderItem = ({ item }) => {
        const backgroundColor = item.color;
        return (
            <Item
                item={item}
                onPress={() => {
                    setBackgroundColor(item.color);
                    saveThemeConfig(item.color);
                }}
                style={{ backgroundColor }}
            />
        );
    };

    return (
        <SafeAreaView style={styles.container}>
            <FlatList
                data={themeData}
                renderItem={renderItem}
                keyExtractor={(item) => item.text}
            />
        </SafeAreaView>
    );
};

const styles = StyleSheet.create({
    container: {
        flex: 1,
        marginTop: StatusBar.currentHeight || 0,
    },
    item: {
        padding: 20,
        marginVertical: 0,
        marginHorizontal: 0,
    },
    title: {
        fontSize: 22,
        color: '#ffffff',
    },
});

export default SettingScreen;

js/navigation/TabNav.js

/* eslint-disable prettier/prettier */
import React, {useContext} from 'react';
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
import {createStackNavigator} from '@react-navigation/stack';
import SchoolScreen from '../screen/SchoolScreen';
import HomeScreen from '../screen/HomeScreen';
import MessageScreen from '../screen/MessageScreen';
import SettingsScreen from '../screen/SettingsScreen';
import AntDesign from 'react-native-vector-icons/AntDesign';
import {ThemeContext} from '../context/ThemeContext';

export default function Navigation({colorScheme}) {
    const [backgroundColor, setBackgroundColor] = useContext(ThemeContext);
    return (
        <Tab.Navigator
            screenOptions={({route}) => ({
                tabBarIcon: ({focused, color, size}) => {
                    if (route.name === 'index') {
                        return <AntDesign name="home" size={size} color={color}/>;
                    } else if (route.name === 'school') {
                        return <AntDesign name="cloudo" size={size} color={color}/>;
                    } else if (route.name === 'message') {
                        return <AntDesign name="mail" size={size} color={color}/>;
                    } else if (route.name === 'setting') {
                        return <AntDesign name="setting" size={size} color={color}/>;
                    }
                },
            })}
            tabBarOptions={{
                activeTintColor: backgroundColor,
            }}
        >
            <Tab.Screen
                name="index"
                component={HomeNavigator}
                options={{title: '首页', headerMode: 'none'}}
            />
            <Tab.Screen
                name="school"
                component={SchoolNavigator}
                options={{title: '校园'}}
            />
            <Tab.Screen
                name="message"
                component={MessageNavigator}
                options={{title: '消息'}}
            />

            <Tab.Screen
                name="setting"
                component={SettingsScreenNavigator}
                options={{title: '设置'}}
            />
        </Tab.Navigator>
    );
}
const Tab = createBottomTabNavigator();
const TabStack = createStackNavigator();

function HomeNavigator() {
    const [backgroundColor, setBackgroundColor] = useContext(ThemeContext);
    return (
        <TabStack.Navigator>
            <TabStack.Screen
                name="School"
                component={HomeScreen}
                options={{
                    headerTitle: '首页',
                    headerLeft: null,
                    headerTitleAlign: 'center',
                    headerStyle: {
                        backgroundColor: backgroundColor,
                    },
                    headerTitleStyle:{
                        color: '#fff',
                    }
                }}
            />
        </TabStack.Navigator>
    );
}

function SchoolNavigator() {
    const [backgroundColor, setBackgroundColor] = useContext(ThemeContext);
    return (
        <TabStack.Navigator>
            <TabStack.Screen
                name="School"
                component={SchoolScreen}
                options={{
                    headerTitle: '校园',
                    headerLeft: null,
                    headerTitleAlign: 'center',
                    headerStyle: {
                        backgroundColor: backgroundColor,
                    },
                    headerTitleStyle:{
                        color: '#fff',
                    }
                }}
            />
        </TabStack.Navigator>
    );
}

function MessageNavigator() {
    const [backgroundColor, setBackgroundColor] = useContext(ThemeContext);
    return (
        <TabStack.Navigator>
            <TabStack.Screen
                name="School"
                component={MessageScreen}
                options={{
                    headerTitle: '消息',
                    headerLeft: null,
                    headerTitleAlign: 'center',
                    headerStyle: {
                        backgroundColor: backgroundColor,
                    },
                    headerTitleStyle:{
                        color: '#fff',
                    }
                }}
            />
        </TabStack.Navigator>
    );
}

function SettingsScreenNavigator() {
    const [backgroundColor, setBackgroundColor] = useContext(ThemeContext);
    return (
        <TabStack.Navigator>
            <TabStack.Screen
                name="School"
                component={SettingsScreen}
                options={{
                    headerTitle: '主题设置',
                    headerLeft: null,
                    headerTitleAlign: 'center',
                    headerStyle: {
                        backgroundColor: backgroundColor,
                    },
                    headerTitleStyle:{
                        color: '#fff',
                    }
                }}
            />
        </TabStack.Navigator>
    );
}

App.js(入口文件)

import React from 'react';
import {
  StyleSheet,
  SafeAreaView,
  StatusBar,
  useColorScheme,
} from 'react-native';
import Navigation from './js/navigation';
import {
  DarkTheme,
  DefaultTheme,
  NavigationContainer,
} from '@react-navigation/native';
import {ThemeProvider} from './js/context/ThemeContext';

const App = () => {
  const colorScheme = useColorScheme();
  return (
    <ThemeProvider>
      <NavigationContainer
        theme={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
        <Navigation />
        <StatusBar barStyle={'light-content'} />
      </NavigationContainer>
    </ThemeProvider>
  );
};

export default App;

import {ThemeProvider} from './js/context/ThemeContext';

const App = () => {
  const colorScheme = useColorScheme();
  return (
    <ThemeProvider>
      <NavigationContainer
        theme={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
        <Navigation />
        <StatusBar barStyle={'light-content'} />
      </NavigationContainer>
    </ThemeProvider>
  );
};

绿色部分为需要增加的部分。

 

项目源码下载:

https://download.csdn.net/download/lxyoucan/12910406

视频教程地址:

https://www.bilibili.com/video/BV1rT4y1c7Jp

 

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值