React Native 动态切换主题

React Native 动态切换主题

创建主题配置和上下文

复制代码
				// ThemeContext.js
			import React, { Component, createContext } from 'react';
			import { Appearance, AsyncStorage } from 'react-native';
			
			// 主题配置
			const themes = {
			  light: {
			    mode: 'light',
			    primary: '#3498db',
			    secondary: '#f39c12',
			    background: '#ffffff',
			    cardBackground: '#f8f9fa',
			    text: '#333333',
			    textSecondary: '#666666',
			    border: '#e0e0e0',
			  },
			  dark: {
			    mode: 'dark',
			    primary: '#2ecc71',
			    secondary: '#e74c3c',
			    background: '#121212',
			    cardBackground: '#1e1e1e',
			    text: '#ffffff',
			    textSecondary: '#bbbbbb',
			    border: '#333333',
			  },
			  blue: {
			    mode: 'blue',
			    primary: '#2980b9',
			    secondary: '#3498db',
			    background: '#ecf0f1',
			    cardBackground: '#bdc3c7',
			    text: '#2c3e50',
			    textSecondary: '#7f8c8d',
			    border: '#95a5a6',
			  }
			};
			
			export const ThemeContext = createContext();
			
			export class ThemeProvider extends Component {
			  state = {
			    theme: themes.light // 默认主题
			  };
			
			  async componentDidMount() {
			    // 尝试加载保存的主题
			    try {
			      const savedTheme = await AsyncStorage.getItem('userTheme');
			      if (savedTheme && themes[savedTheme]) {
			        this.setState({ theme: themes[savedTheme] });
			      } else {
			        // 没有保存的主题则使用系统主题
			        const systemTheme = Appearance.getColorScheme() === 'dark' ? themes.dark : themes.light;
			        this.setState({ theme: systemTheme });
			      }
			    } catch (error) {
			      console.error('加载主题失败:', error);
			    }
			
			    // 监听系统主题变化
			    this.appearanceListener = Appearance.addChangeListener(({ colorScheme }) => {
			      if (!this.state.userSelectedTheme) { // 如果用户没有手动选择主题
			        this.setState({
			          theme: colorScheme === 'dark' ? themes.dark : themes.light
			        });
			      }
			    });
			  }
			
			  componentWillUnmount() {
			    if (this.appearanceListener) {
			      this.appearanceListener.remove();
			    }
			  }
			
			  toggleTheme = () => {
			    const newTheme = this.state.theme.mode === 'light' ? themes.dark : themes.light;
			    this.setTheme(newTheme.mode);
			  };
			
			  setTheme = async (themeName) => {
			    if (themes[themeName]) {
			      this.setState({ 
			        theme: themes[themeName],
			        userSelectedTheme: true 
			      });
			      try {
			        await AsyncStorage.setItem('userTheme', themeName);
			      } catch (error) {
			        console.error('保存主题失败:', error);
			      }
			    }
			  };
			
			  render() {
			    return (
			      <ThemeContext.Provider
			        value={{
			          theme: this.state.theme,
			          toggleTheme: this.toggleTheme,
			          setTheme: this.setTheme,
			          themes: Object.keys(themes) // 所有可用主题列表
			        }}
			      >
			        {this.props.children}
			      </ThemeContext.Provider>
			    );
			  }
			}

创建主题化高阶组件

复制代码
// withTheme.js
import React from 'react';
import { ThemeContext } from './ThemeContext';

export function withTheme(Component) {
  return function ThemedComponent(props) {
    return (
      <ThemeContext.Consumer>
        {context => <Component {...props} {...context} />}
      </ThemeContext.Consumer>
    );
  };
}

主应用组件

复制代码
// App.js
import React from 'react';
import { ThemeProvider } from './ThemeContext';
import MainScreen from './MainScreen';

export default class App extends React.Component {
  render() {
    return (
      <ThemeProvider>
        <MainScreen />
      </ThemeProvider>
    );
  }
}

主屏幕组件(类组件形式)

复制代码
// MainScreen.js
import React from 'react';
import { View, Text, StyleSheet, TouchableOpacity } from 'react-native';
import { withTheme } from './withTheme';

class MainScreen extends React.Component {
  render() {
    const { theme, toggleTheme, setTheme, themes } = this.props;
    
    return (
      <View style={[styles.container, { backgroundColor: theme.background }]}>
        <Text style={[styles.title, { color: theme.text }]}>当前主题: {theme.mode}</Text>
        
        <TouchableOpacity 
          style={[styles.button, { backgroundColor: theme.primary }]}
          onPress={toggleTheme}
        >
          <Text style={styles.buttonText}>切换主题</Text>
        </TouchableOpacity>
        
        <View style={styles.themeOptions}>
          {themes.map(themeName => (
            <TouchableOpacity 
              key={themeName}
              style={[
                styles.themeButton, 
                { 
                  backgroundColor: themes[themeName].primary,
                  marginBottom: 10
                }
              ]}
              onPress={() => setTheme(themeName)}
            >
              <Text style={styles.buttonText}>{themeName}</Text>
            </TouchableOpacity>
          ))}
        </View>
        
        <View style={[styles.card, { backgroundColor: theme.cardBackground }]}>
          <Text style={{ color: theme.text }}>这是一个卡片示例</Text>
          <Text style={{ color: theme.textSecondary }}>次要文本颜色</Text>
          <View style={[styles.divider, { backgroundColor: theme.border }]} />
          <Text style={{ color: theme.text }}>边框颜色示例</Text>
        </View>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
  },
  title: {
    fontSize: 24,
    marginBottom: 30,
    fontWeight: 'bold',
  },
  button: {
    padding: 15,
    borderRadius: 8,
    marginBottom: 20,
    width: 200,
    alignItems: 'center',
  },
  themeButton: {
    padding: 12,
    borderRadius: 6,
    marginHorizontal: 5,
    width: 100,
    alignItems: 'center',
  },
  buttonText: {
    color: 'white',
    fontWeight: 'bold',
  },
  themeOptions: {
    flexDirection: 'row',
    flexWrap: 'wrap',
    justifyContent: 'center',
    marginTop: 20,
    marginBottom: 30,
  },
  card: {
    width: '90%',
    padding: 20,
    borderRadius: 10,
    marginTop: 20,
  },
  divider: {
    height: 1,
    width: '100%',
    marginVertical: 15,
  }
});

export default withTheme(MainScreen);
相关推荐
喂哟咦8 小时前
关于用codex两周写了一个epub阅读器这件事
前端·javascript
CDwenhuohuo8 小时前
前端文件预览
开发语言·前端·javascript
008爬虫实战录8 小时前
【最新猿人学】 验证码 - 图文点选 文字验证码识别
前端·javascript
一叶飘零晋8 小时前
【(一)Electron 使用之如何用vite+vue3搭建初始框架】
前端·javascript·electron
光影少年9 小时前
前端SSR和ssg区别
前端·vue.js·人工智能·学习·react.js
祖国的好青年9 小时前
VS Code 搭建 React Native 开发环境(Windows 实战指南)
android·windows·react native·react.js
恶猫9 小时前
网页自动化模拟操作时,模拟真实按键触发事件【终级方案】
前端·javascript·自动化·vue·网页模拟
一个扣子10 小时前
性能面板解读:通过 Hermes Runtime 测量函数执行耗时
react native·chrome devtools·hermes·性能面板·函数耗时·performance api
ZC跨境爬虫10 小时前
跟着 MDN 学 HTML day_2:(表单分组与高级输入控件实战)
前端·javascript·css·ui·html
千寻girling11 小时前
滑动窗口刷了快一个月(26天)了 , 还没有刷完. | 含(操作系统学什么的Java 后端)
java·开发语言·javascript·c++·人工智能·后端·python