我可以在 React Native 中制作动态样式吗?
Can I make dynamic styles in React Native?
假设我有一个渲染如下的组件:
<View style={jewelStyle}></View>
其中 jewelStyle =
{
borderRadius: 10,
backgroundColor: '#FFEFCC',
width: 20,
height: 20,
},
如何使背景颜色动态且随机分配?我试过了
{
borderRadius: 10,
backgroundColor: getRandomColor(),
width: 20,
height: 20,
},
但这使得所有 View 实例都具有相同的颜色,我希望每个实例都是唯一的。
有什么建议吗?
我通常会按照以下方式做一些事情:
<View style={this.jewelStyle()} />
...
jewelStyle = function(options) {
return {
borderRadius: 12,
background: randomColor(),
}
}
每次渲染 View 时,都会实例化一个新的样式对象,并使用与之关联的随机颜色。当然,这意味着每次重新渲染组件时颜色都会改变,这可能不是您想要的。相反,您可以这样做:
var myColor = randomColor()
<View style={jewelStyle(myColor)} />
...
jewelStyle = function(myColor) {
return {
borderRadius: 10,
background: myColor,
}
}
你会想要这样的东西:
var RandomBgApp = React.createClass({
render: function() {
var getRandomColor = function() {
var letters = '0123456789ABCDEF'.split('');
var color = '#';
for (var i = 0; i < 6; i++ ) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
};
var rows = [
{ name: 'row 1'},
{ name: 'row 2'},
{ name: 'row 3'}
];
var rowNodes = rows.map(function(row) {
return <Text style={{backgroundColor:getRandomColor()}}>{row.name}</Text>
});
return (
<View>
{rowNodes}
</View>
);
}
});
在这个例子中,我采用包含组件中行数据的行数组,并将其映射到文本组件数组中。每次创建新的文本组件时,我都使用内联样式来调用 getRandomColor
函数。
您的代码的问题在于您只定义了一次样式,因此 getRandomColor 仅在您定义样式时被调用一次。
可以,实际上,您应该使用 StyleSheet.create
来创建样式。
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View
} from 'react-native';
class Header extends Component {
constructor(props){
super(props);
}
render() {
const { title, style } = this.props;
const { header, text } = defaultStyle;
const combineStyles = StyleSheet.flatten([header, style]);
return (
<View style={ combineStyles }>
<Text style={ text }>
{ title }
</Text>
</View>
);
}
}
const defaultStyle = StyleSheet.create({
header: {
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#fff',
height: 60,
paddingTop: 15,
shadowColor: '#000',
shadowOffset: { width: 0, height: 3 },
shadowOpacity: 0.4,
elevation: 2,
position: 'relative'
},
text: {
color: '#0d4220',
fontSize: 16
}
});
export default Header;
然后:
<Header title="HOME" style={ {backgroundColor: '#10f1f0'} } />
我知道有几个答案,但我认为最好和最简单的是使用状态 "To change" 是状态目的。
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
style: {
backgroundColor: "white"
}
};
}
onPress = function() {
this.setState({style: {backgroundColor: "red"}});
}
render() {
return (
...
<View style={this.state.style}></View>
...
)
}
}
您可以将状态值直接绑定到样式对象。这是一个例子:
class Timer extends Component{
constructor(props){
super(props);
this.state = {timer: 0, color: '#FF0000'};
setInterval(() => {
this.setState({timer: this.state.timer + 1, color: this.state.timer % 2 == 0 ? '#FF0000' : '#0000FF'});
}, 1000);
}
render(){
return (
<View>
<Text>Timer:</Text>
<Text style={{backgroundColor: this.state.color}}>{this.state.timer}</Text>
</View>
);
}
}
如果您仍想利用 StyleSheet.create
并且还想拥有动态样式,请试试这个:
const Circle = ({initial}) => {
const initial = user.pending ? user.email[0] : user.firstName[0];
const colorStyles = {
backgroundColor: randomColor()
};
return (
<View style={[styles.circle, colorStyles]}>
<Text style={styles.text}>{initial.toUpperCase()}</Text>
</View>
);
};
const styles = StyleSheet.create({
circle: {
height: 40,
width: 40,
borderRadius: 30,
overflow: 'hidden'
},
text: {
fontSize: 12,
lineHeight: 40,
color: '#fff',
textAlign: 'center'
}
});
请注意 View
的 style
属性 是如何设置为将样式表与动态样式组合在一起的数组。
在语法上有一些问题。
这对我有用
<Text style={[styles.textStyle,{color: 'red'}]}> Hello </Text>
const styles = StyleSheet.create({
textStyle :{
textAlign: 'center',
fontFamily: 'Arial',
fontSize: 16
}
});
最简单的是我的:
<TextInput
style={[
styles.default,
this.props.singleSourceOfTruth ?
{ backgroundColor: 'black' }
: { backgroundColor: 'white' }
]}/>
例如,如果您使用的是带有滤镜的屏幕,并且您想设置滤镜是否被选中的背景,您可以这样做:
<TouchableOpacity style={this.props.venueFilters.includes('Bar')?styles.filterBtnActive:styles.filterBtn} onPress={()=>this.setFilter('Bar')}>
<Text numberOfLines={1}>
Bar
</Text>
</TouchableOpacity>
设置的过滤器是:
setVenueFilter(filter){
var filters = this.props.venueFilters;
filters.push(filter);
console.log(filters.includes('Bar'), "Inclui Bar");
this.setState(previousState => {
return { updateFilter: !previousState.updateFilter };
});
this.props.setVenueFilter(filters);
}
PS:函数this.props.setVenueFilter(filters)
是一个redux动作,this.props.venueFilters
是一个redux状态。
是的,您可以制作动态样式。您可以从组件传递值。
先创建StyleSheetFactory.js
import { StyleSheet } from "react-native";
export default class StyleSheetFactory {
static getSheet(backColor) {
return StyleSheet.create({
jewelStyle: {
borderRadius: 10,
backgroundColor: backColor,
width: 20,
height: 20,
}
})
}
}
然后按照以下方式在您的组件中使用它
import React from "react";
import { View } from "react-native";
import StyleSheetFactory from './StyleSheetFactory'
class Main extends React.Component {
getRandomColor = () => {
var letters = "0123456789ABCDEF";
var color = "#";
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
};
render() {
return (
<View>
<View
style={StyleSheetFactory.getSheet(this.getRandomColor()).jewelStyle}
/>
<View
style={StyleSheetFactory.getSheet(this.getRandomColor()).jewelStyle}
/>
<View
style={StyleSheetFactory.getSheet(this.getRandomColor()).jewelStyle}
/>
</View>
);
}
}
使用对象展开运算符“...”对我有用:
<View style={{...jewelStyle, ...{'backgroundColor': getRandomColor()}}}></View>
万一有人需要申请条件
selectedMenuUI = function(value) {
if(value==this.state.selectedMenu){
return {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 20,
paddingVertical: 10,
backgroundColor: 'rgba(255,255,255,0.3)',
borderRadius: 5
}
}
return {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 20,
paddingVertical: 10
}
}
以下是对我有用的方法:
render() {
const { styleValue } = this.props;
const dynamicStyleUpdatedFromProps = {
height: styleValue,
width: styleValue,
borderRadius: styleValue,
}
return (
<View style={{ ...styles.staticStyleCreatedFromStyleSheet, ...dynamicStyleUpdatedFromProps }} />
);
}
出于某种原因,这是我的唯一正确更新的方式。
我知道这已经很晚了,但对于仍然想知道这里有一个简单解决方案的人来说。
您可以为样式创建一个数组:
this.state ={
color: "#fff"
}
style={[
styles.jewelstyle, {
backgroundColor: this.state.BGcolor
}
第二个将覆盖样式表中规定的任何原始背景颜色。然后有一个改变颜色的函数:
generateNewColor(){
var randomColor = '#'+Math.floor(Math.random()*16777215).toString(16);
this.setState({BGcolor: randomColor})
}
这将生成随机的十六进制颜色。然后只要调用那个函数,砰的一声,新的背景颜色。
实际上,您可以将 StyleSheet.create
对象编写为具有函数值的键,它可以正常工作,但在 TypeScript 中存在类型问题:
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
const SomeComponent = ({ bgColor }) => (
<View style={styles.wrapper(bgColor)}>
<Text style={styles.text}>3333</Text>
</View>
);
const styles = StyleSheet.create({
wrapper: color => ({
flex: 1,
backgroundColor: color,
}),
text: {
color: 'red',
},
});
你可以这样做。
在你的组件中:
const getRandomColor = () => {
// you can use your component props here.
}
<View style={[styles.jewelStyle, {backgroundColor: getRandomColor()}]} />
使用样式表创建您的样式:
const styles = StyleSheet.create({
jewelStyle: {
backgroundColor: 'red',
},
});
import React, { useContext, useMemo } from 'react';
import { Text, StyleSheet, View } from 'react-native';
import colors from '../utils/colors';
import ThemeContext from './../contexts/ThemeContext';
export default (props) => {
const { theme } = useContext(ThemeContext);
// Constructing styles for current theme
const styles = useMemo(() => createStyles(theme), [theme]);
return (
<View style={styles.container}>
<Text style={styles.label}>{label}</Text>
</View>
);
};
const createStyles = (theme: AppTheme) =>
StyleSheet.create({
container: { width: '100%', position: 'relative', backgroundColor: colors[theme].background },
label: {
fontSize: 13,
fontWeight: 'bold',
},
});
colors.ts
export type AppTheme = 'dark' | 'light';
const light: Colors = {
background: '#FFFFFF',
onBackground: '#333333',
gray: '#999999',
grayLight: '#DDDDDD',
red: 'red',
};
const dark: Colors = {
background: '#333333',
onBackground: '#EEEEEE',
gray: '#999999',
grayLight: '#DDDDDD',
red: 'red',
};
const colors = {
dark,
light,
primary: '#2E9767',
secondary: '#F6D130',
};
export default colors;
你可以使用 styled-components 来响应原生,它会为你提供动态样式,就像 emotion 或 web 的 styled-components 一样。
<View
style={[styles.categoryItem,{marginTop: index <= numOfColumns-1 ? 10 : 0 }]}
>
如果您遵循 React-Native 的函数式方法,您可以使用名为 dynamic-styles
的包来尝试准确解决您的问题。
// -- theme.js ------------------------------------------------------
// Initialization of a StyleSheet instance called 'styleSheet'
export const styleSheet = createStyleSheet({
theme: /* optional theme */
});
// -- MyComponent.js -----------------------------------------------
// Create dynamic stylesheet that has access
// to the previously specified theme and parameters
const useStyles = styleSheet.create(({theme, params}) => ({
root: /* Dynamic Styles */,
button: /* Dynamic Styles */,
text: /* Dynamic Styles */,
}));
const MyComponent = (props) => {
// Access dynamic styles using the created 'useStyles()' hook
// and specify the corresponding parameters
const { styles } = useStyles({ color: props.color, fontSize: 10 });
return (
<div className={styles.root}>
{/* */}
</div>
);
}
它基本上允许您创建 dynamic
样式表
link 使用 React hook
模式将它们转换为功能组件。
假设我有一个渲染如下的组件:
<View style={jewelStyle}></View>
其中 jewelStyle =
{
borderRadius: 10,
backgroundColor: '#FFEFCC',
width: 20,
height: 20,
},
如何使背景颜色动态且随机分配?我试过了
{
borderRadius: 10,
backgroundColor: getRandomColor(),
width: 20,
height: 20,
},
但这使得所有 View 实例都具有相同的颜色,我希望每个实例都是唯一的。
有什么建议吗?
我通常会按照以下方式做一些事情:
<View style={this.jewelStyle()} />
...
jewelStyle = function(options) {
return {
borderRadius: 12,
background: randomColor(),
}
}
每次渲染 View 时,都会实例化一个新的样式对象,并使用与之关联的随机颜色。当然,这意味着每次重新渲染组件时颜色都会改变,这可能不是您想要的。相反,您可以这样做:
var myColor = randomColor()
<View style={jewelStyle(myColor)} />
...
jewelStyle = function(myColor) {
return {
borderRadius: 10,
background: myColor,
}
}
你会想要这样的东西:
var RandomBgApp = React.createClass({
render: function() {
var getRandomColor = function() {
var letters = '0123456789ABCDEF'.split('');
var color = '#';
for (var i = 0; i < 6; i++ ) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
};
var rows = [
{ name: 'row 1'},
{ name: 'row 2'},
{ name: 'row 3'}
];
var rowNodes = rows.map(function(row) {
return <Text style={{backgroundColor:getRandomColor()}}>{row.name}</Text>
});
return (
<View>
{rowNodes}
</View>
);
}
});
在这个例子中,我采用包含组件中行数据的行数组,并将其映射到文本组件数组中。每次创建新的文本组件时,我都使用内联样式来调用 getRandomColor
函数。
您的代码的问题在于您只定义了一次样式,因此 getRandomColor 仅在您定义样式时被调用一次。
可以,实际上,您应该使用 StyleSheet.create
来创建样式。
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View
} from 'react-native';
class Header extends Component {
constructor(props){
super(props);
}
render() {
const { title, style } = this.props;
const { header, text } = defaultStyle;
const combineStyles = StyleSheet.flatten([header, style]);
return (
<View style={ combineStyles }>
<Text style={ text }>
{ title }
</Text>
</View>
);
}
}
const defaultStyle = StyleSheet.create({
header: {
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#fff',
height: 60,
paddingTop: 15,
shadowColor: '#000',
shadowOffset: { width: 0, height: 3 },
shadowOpacity: 0.4,
elevation: 2,
position: 'relative'
},
text: {
color: '#0d4220',
fontSize: 16
}
});
export default Header;
然后:
<Header title="HOME" style={ {backgroundColor: '#10f1f0'} } />
我知道有几个答案,但我认为最好和最简单的是使用状态 "To change" 是状态目的。
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
style: {
backgroundColor: "white"
}
};
}
onPress = function() {
this.setState({style: {backgroundColor: "red"}});
}
render() {
return (
...
<View style={this.state.style}></View>
...
)
}
}
您可以将状态值直接绑定到样式对象。这是一个例子:
class Timer extends Component{
constructor(props){
super(props);
this.state = {timer: 0, color: '#FF0000'};
setInterval(() => {
this.setState({timer: this.state.timer + 1, color: this.state.timer % 2 == 0 ? '#FF0000' : '#0000FF'});
}, 1000);
}
render(){
return (
<View>
<Text>Timer:</Text>
<Text style={{backgroundColor: this.state.color}}>{this.state.timer}</Text>
</View>
);
}
}
如果您仍想利用 StyleSheet.create
并且还想拥有动态样式,请试试这个:
const Circle = ({initial}) => {
const initial = user.pending ? user.email[0] : user.firstName[0];
const colorStyles = {
backgroundColor: randomColor()
};
return (
<View style={[styles.circle, colorStyles]}>
<Text style={styles.text}>{initial.toUpperCase()}</Text>
</View>
);
};
const styles = StyleSheet.create({
circle: {
height: 40,
width: 40,
borderRadius: 30,
overflow: 'hidden'
},
text: {
fontSize: 12,
lineHeight: 40,
color: '#fff',
textAlign: 'center'
}
});
请注意 View
的 style
属性 是如何设置为将样式表与动态样式组合在一起的数组。
在语法上有一些问题。 这对我有用
<Text style={[styles.textStyle,{color: 'red'}]}> Hello </Text>
const styles = StyleSheet.create({
textStyle :{
textAlign: 'center',
fontFamily: 'Arial',
fontSize: 16
}
});
最简单的是我的:
<TextInput
style={[
styles.default,
this.props.singleSourceOfTruth ?
{ backgroundColor: 'black' }
: { backgroundColor: 'white' }
]}/>
例如,如果您使用的是带有滤镜的屏幕,并且您想设置滤镜是否被选中的背景,您可以这样做:
<TouchableOpacity style={this.props.venueFilters.includes('Bar')?styles.filterBtnActive:styles.filterBtn} onPress={()=>this.setFilter('Bar')}>
<Text numberOfLines={1}>
Bar
</Text>
</TouchableOpacity>
设置的过滤器是:
setVenueFilter(filter){
var filters = this.props.venueFilters;
filters.push(filter);
console.log(filters.includes('Bar'), "Inclui Bar");
this.setState(previousState => {
return { updateFilter: !previousState.updateFilter };
});
this.props.setVenueFilter(filters);
}
PS:函数this.props.setVenueFilter(filters)
是一个redux动作,this.props.venueFilters
是一个redux状态。
是的,您可以制作动态样式。您可以从组件传递值。
先创建StyleSheetFactory.js
import { StyleSheet } from "react-native";
export default class StyleSheetFactory {
static getSheet(backColor) {
return StyleSheet.create({
jewelStyle: {
borderRadius: 10,
backgroundColor: backColor,
width: 20,
height: 20,
}
})
}
}
然后按照以下方式在您的组件中使用它
import React from "react";
import { View } from "react-native";
import StyleSheetFactory from './StyleSheetFactory'
class Main extends React.Component {
getRandomColor = () => {
var letters = "0123456789ABCDEF";
var color = "#";
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
};
render() {
return (
<View>
<View
style={StyleSheetFactory.getSheet(this.getRandomColor()).jewelStyle}
/>
<View
style={StyleSheetFactory.getSheet(this.getRandomColor()).jewelStyle}
/>
<View
style={StyleSheetFactory.getSheet(this.getRandomColor()).jewelStyle}
/>
</View>
);
}
}
使用对象展开运算符“...”对我有用:
<View style={{...jewelStyle, ...{'backgroundColor': getRandomColor()}}}></View>
万一有人需要申请条件
selectedMenuUI = function(value) {
if(value==this.state.selectedMenu){
return {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 20,
paddingVertical: 10,
backgroundColor: 'rgba(255,255,255,0.3)',
borderRadius: 5
}
}
return {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 20,
paddingVertical: 10
}
}
以下是对我有用的方法:
render() {
const { styleValue } = this.props;
const dynamicStyleUpdatedFromProps = {
height: styleValue,
width: styleValue,
borderRadius: styleValue,
}
return (
<View style={{ ...styles.staticStyleCreatedFromStyleSheet, ...dynamicStyleUpdatedFromProps }} />
);
}
出于某种原因,这是我的唯一正确更新的方式。
我知道这已经很晚了,但对于仍然想知道这里有一个简单解决方案的人来说。
您可以为样式创建一个数组:
this.state ={
color: "#fff"
}
style={[
styles.jewelstyle, {
backgroundColor: this.state.BGcolor
}
第二个将覆盖样式表中规定的任何原始背景颜色。然后有一个改变颜色的函数:
generateNewColor(){
var randomColor = '#'+Math.floor(Math.random()*16777215).toString(16);
this.setState({BGcolor: randomColor})
}
这将生成随机的十六进制颜色。然后只要调用那个函数,砰的一声,新的背景颜色。
实际上,您可以将 StyleSheet.create
对象编写为具有函数值的键,它可以正常工作,但在 TypeScript 中存在类型问题:
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
const SomeComponent = ({ bgColor }) => (
<View style={styles.wrapper(bgColor)}>
<Text style={styles.text}>3333</Text>
</View>
);
const styles = StyleSheet.create({
wrapper: color => ({
flex: 1,
backgroundColor: color,
}),
text: {
color: 'red',
},
});
你可以这样做。
在你的组件中:
const getRandomColor = () => {
// you can use your component props here.
}
<View style={[styles.jewelStyle, {backgroundColor: getRandomColor()}]} />
使用样式表创建您的样式:
const styles = StyleSheet.create({
jewelStyle: {
backgroundColor: 'red',
},
});
import React, { useContext, useMemo } from 'react';
import { Text, StyleSheet, View } from 'react-native';
import colors from '../utils/colors';
import ThemeContext from './../contexts/ThemeContext';
export default (props) => {
const { theme } = useContext(ThemeContext);
// Constructing styles for current theme
const styles = useMemo(() => createStyles(theme), [theme]);
return (
<View style={styles.container}>
<Text style={styles.label}>{label}</Text>
</View>
);
};
const createStyles = (theme: AppTheme) =>
StyleSheet.create({
container: { width: '100%', position: 'relative', backgroundColor: colors[theme].background },
label: {
fontSize: 13,
fontWeight: 'bold',
},
});
colors.ts
export type AppTheme = 'dark' | 'light';
const light: Colors = {
background: '#FFFFFF',
onBackground: '#333333',
gray: '#999999',
grayLight: '#DDDDDD',
red: 'red',
};
const dark: Colors = {
background: '#333333',
onBackground: '#EEEEEE',
gray: '#999999',
grayLight: '#DDDDDD',
red: 'red',
};
const colors = {
dark,
light,
primary: '#2E9767',
secondary: '#F6D130',
};
export default colors;
你可以使用 styled-components 来响应原生,它会为你提供动态样式,就像 emotion 或 web 的 styled-components 一样。
<View
style={[styles.categoryItem,{marginTop: index <= numOfColumns-1 ? 10 : 0 }]}
>
如果您遵循 React-Native 的函数式方法,您可以使用名为 dynamic-styles
的包来尝试准确解决您的问题。
// -- theme.js ------------------------------------------------------
// Initialization of a StyleSheet instance called 'styleSheet'
export const styleSheet = createStyleSheet({
theme: /* optional theme */
});
// -- MyComponent.js -----------------------------------------------
// Create dynamic stylesheet that has access
// to the previously specified theme and parameters
const useStyles = styleSheet.create(({theme, params}) => ({
root: /* Dynamic Styles */,
button: /* Dynamic Styles */,
text: /* Dynamic Styles */,
}));
const MyComponent = (props) => {
// Access dynamic styles using the created 'useStyles()' hook
// and specify the corresponding parameters
const { styles } = useStyles({ color: props.color, fontSize: 10 });
return (
<div className={styles.root}>
{/* */}
</div>
);
}
它基本上允许您创建 dynamic
样式表
link 使用 React hook
模式将它们转换为功能组件。