我在我的应用程序中使用 React Navigation 默认和深色主题。用户可以通过“切换”按钮更改主题,一切正常。
现在我想为默认主题和深色主题添加其他颜色。 所以默认情况下他们有这样的东西:
Object {
"background": "rgb(1, 1, 1)",
"border": "rgb(39, 39, 41)",
"card": "rgb(18, 18, 18)",
"notification": "rgb(255, 69, 58)",
"primary": "rgb(10, 132, 255)",
"text": "rgb(229, 229, 231)",
}
我想做的是附加类似的内容:
"commentText": "rgb(200, 200, 100)"
我目前以这种方式调用主题:
import { useTheme } from "@react-navigation/native";
const { colors } = useTheme();
const styles = StyleSheet.create({
text: {
fontSize: 16,
color: colors.text,
},
});
// in my component ...
<Text style={styles.text}>Date format</Text>
最好的方法是什么?我是否需要完全定义自己的自定义主题,包含原始颜色加上我的颜色?有什么方法可以简单地附加到原始内容上吗?
更新:
我部分遵循了本指南,并决定创建自己的主题并添加更多条目(在本文中不可见)。 现在我当前的挑战是直接在定义样式的文件中移动颜色定义(例如
typography.js
)。如果我使用定义的颜色(例如border: "#d8d8d8"
),它效果很好,但我希望它能够选择主题(例如color: colors.text
)。
问题是
useTheme()
只能在React函数组件或自定义React Hook函数中调用。
例如,我如何在 typography.js
中使用它?
下面提供代码,请注意评论。
Home.js
import { useTheme } from "@react-navigation/native";
import React, { useContext, useEffect, useState } from "react";
import {
Dimensions,
StyleSheet,
Text,
TouchableOpacity,
View,
} from "react-native";
import { borders, buttons, layout, typography } from "../styles";
const Home = ({ navigation }) => {
const { colors } = useTheme();
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: colors.background // Works fine
},
buttonText: {
...typography.buttonText,
color: colors.text, // I would like to move this to typography.js
}
});
return (
<>
<View style={styles.container}>
<Text style={styles.buttonText}>blabla</Text>
// More code here....
</View>
</>
);
};
export default Home;
./styles/index.js
import * as themes from "./themes";
import * as typography from "./typography";
export {
themes,
typography
};
./styles/themes.js
export const MyDefaultTheme = {
dark: false,
colors: {
background: "#f2f2f2",
border: "#d8d8d8",
card: "#ffffff",
notification: "#ff3b30",
primary: "#007aff",
text: "#1c1c1e",
},
};
export const MyDarkTheme = {
dark: true,
colors: {
background: "#010101",
border: "#272729",
card: "#121212",
notification: "#ff453a",
primary: "#0a84ff",
text: "#e5e5e7",
},
};
./styles/typography.js
import { useTheme } from "@react-navigation/native"; // // This isn't working
const { colors } = useTheme(); // This isn't working
export const textHeader = {
fontWeight: "bold",
fontSize: 30,
textAlign: "center",
marginBottom: 20,
};
export const buttonText = {
fontSize: 14,
textAlign: "center",
color: colors.text // This is not working
};
您正在寻找的是外观API。限制是鼓励您使用内联样式,因为主题可能会发生变化,例如从白天切换到晚上。
在您的示例代码中,您在组件外部调用 useTheme() ,因此它不起作用。您的内联颜色样式的原始解决方案似乎正是 React Native 团队推荐的。
我在最近的应用程序中也遇到了类似的问题。不幸的是,我发现不可能根据 React 组件之外的主题获取
colors
的动态值,例如在 colors.js
等实用程序文件中。
因此,为了解决这个问题,我的方法是使用
makeStyles
函数,根据传递给它的主题或颜色动态生成样式。
这使我能够保持样式模块化,并确保可以在应用程序中一致地使用主题颜色,而无需直接将 useTheme
导入到样式文件中。
以下是实施方法:
makeStyles
实用程序makeStyles
函数
该函数采用主题或颜色作为参数并动态返回样式。import { StyleSheet } from "react-native";
const makeStyles = (theme) => {
const { colors } = theme;
return StyleSheet.create({
container: {
flex: 1,
backgroundColor: colors.background, // using background color from theme
},
buttonText: {
fontSize: 14,
textAlign: "center",
color: colors.text, // using text color from theme
},
textHeader: {
fontWeight: "bold",
fontSize: 30,
textAlign: "center",
marginBottom: 20,
color: colors.primary, // using primary color from theme
},
});
};
export default makeStyles;
将主题传递给组件中的
makeStyles
在组件内使用
useTheme
获取当前主题并将其传递给 makeStyles
。
import { useTheme } from "@react-navigation/native";
import React, { useMemo } from "react";
import { Text, View } from "react-native";
import makeStyles from "../styles/makeStyles";
const Home = () => {
const { colors } = useTheme();
// Memoize the styles to avoid unnecessary re-creations
const styles = useMemo(() => makeStyles({ colors }), [colors]);
return (
<View style={styles.container}>
<Text style={styles.textHeader}>Welcome to Home</Text>
<Text style={styles.buttonText}>Press Me</Text>
</View>
);
};
export default Home;
您需要在 Redux 中存储一个 Value,基于这个 Value,您可以通过在每个组件中获取该值来更改每个组件的颜色。
只需在 App.js 中调度操作并根据 redux 中存储的值应用自定义颜色即可。
useEffect(() => {
subscription = Appearance.addChangeListener(({ colorScheme }) => {
if (colorScheme === 'light') {
dispatch(setMode(false));
} else {
dispatch(setMode(true));
}
});
return () => subscription && subscription.remove();
}, []);