【问题标题】:Can I make dynamic styles in React Native?我可以在 React Native 中制作动态样式吗?
【发布时间】:2015-06-04 11:58:50
【问题描述】:

假设我有一个这样的渲染组件:

<View style={jewelStyle}></View>

其中jewelStyle =

  {
    borderRadius: 10,
    backgroundColor: '#FFEFCC',
    width: 20,
    height: 20,
  },

如何使背景颜色动态且随机分配?我试过了

  {
    borderRadius: 10,
    backgroundColor: getRandomColor(),
    width: 20,
    height: 20,
  },

但这使得 View 的所有实例都具有相同的颜色,我希望每个实例都是唯一的。

有什么建议吗?

【问题讨论】:

    标签: css reactjs react-native


    【解决方案1】:

    我通常会做以下事情:

    <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,
       }
     }
    

    【讨论】:

    • 这个方法根本不使用样式表。无论如何,那些用Stylesheet.create() 声明样式表的目的是什么?
    • @fatuhoku 当您需要在多个地方重复使用相同的样式时,它非常有用
    • 使用 Stylesheet.create 有很多好处吗?
    • @DominicTobias Stylesheet.create 只将样式打包并“发送”到本地区域一次。这意味着当您多次重用相同的样式或多次加载相同的组件时,它将重用该样式,而不是再次打包和“发送”。例如,如果您正在加载 3000 个样式行,您会感受到性能的显着提升。
    【解决方案2】:

    是的,您可以,实际上,您应该使用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'} } />
    

    【讨论】:

    • 这个答案展示了一个很好的例子,其中样式在样式表中定义,但以后可以在组件中覆盖
    • AFAIK 使用 StyleSheet.flatten 只是抛弃了来自 StyleSheet.create 的任何优化,如文档中所述:“注意:请谨慎行事,因为滥用它会在优化方面给您带来负担。ID 可以通过桥接进行优化和一般的内存。直接引用样式对象会剥夺你的这些优化。 (facebook.github.io/react-native/docs/stylesheet.html)。
    • 我认为您正在寻找的方法是 StyleSheet.compose 而不是 StyleSheet.flatten 因为它将 2 个样式对象组合在一起(或组合它们......)。我还没有查看源代码来确认这是否比简单地将一组样式对象传递给 style 道具有什么好处,但它绝对应该击败 flatten,因为这实际上是在查找原始样式值created 样式对象。
    • 使用 flatten 有什么好处.. 如果我喜欢 style={[header, style]} 怎么办?
    【解决方案3】:

    如果您仍想利用 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'
        }
    });
    

    注意Viewstyle 属性是如何设置为将样式表与动态样式相结合的数组。

    【讨论】:

      【解决方案4】:

      最简单的是我的:

      <TextInput
        style={[
          styles.default,
          this.props.singleSourceOfTruth ?
          { backgroundColor: 'black' } 
          : { backgroundColor: 'white' }
      ]}/>
      

      【讨论】:

      • 我编辑了发布的答案以符合@Sarahcartenz 评论
      • 好极了,确实很棒。也可以使用此解决方案覆盖属性,对吗?最后一个覆盖上一个
      【解决方案5】:

      语法上有问题。 这对我有用

      <Text style={[styles.textStyle,{color: 'red'}]}> Hello </Text>
      
      const styles = StyleSheet.create({
         textStyle :{
            textAlign: 'center',   
            fontFamily: 'Arial',
            fontSize: 16
        }
        });
      

      【讨论】:

      • 谢谢@Yogesh,这正是我要找的。我想利用样式,但能够在我需要的东西上添加更多。
      【解决方案6】:

      你会想要这样的:

      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>
              );
      
          }
      });
      

      在此示例中,我采用包含组件中行数据的 rows 数组,并将其映射到 Text 组件数组中。每次创建新的 Text 组件时,我都会使用内联样式调用 getRandomColor 函数。

      您的代码的问题是您定义了一次样式,因此 getRandomColor 只被调用一次 - 当您定义样式时。

      【讨论】:

      • 嗨 Colin,谢谢你,但我怎样才能同时传递其他样式参数?
      • 你的意思是 style={{backgroundColor:getRandomColor(), color: 'black'}}?
      • 谢谢,这可行,但我接受了另一个答案,因为它有助于展示如何一次性传递一组样式。
      【解决方案7】:

      我知道这已经很晚了,但是对于仍然想知道这里有一个简单的解决方案的人来说。

      您可以为样式创建一个数组:

      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})
      }
      

      这将生成一个随机的十六进制颜色。然后随时调用该函数并 bam,新的背景颜色。

      【讨论】:

        【解决方案8】:

        实际上,您可以将 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',
          },
        });
        
        

        【讨论】:

        • 该代码不适用于 React 16.13.1。 styles.wrapper is not a function 太糟糕了,本来会很酷的。
        【解决方案9】:

        使用对象扩展运算符“...”对我有用:

        <View style={{...jewelStyle, ...{'backgroundColor': getRandomColor()}}}></View>
        

        【讨论】:

          【解决方案10】:

          是的,您可以制作动态样式。您可以从组件中传递值。

          首先创建 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>
              );
            }
          }
          

          【讨论】:

            【解决方案11】:

            我知道有几个答案,但我认为最好和最简单的是使用状态“改变”是状态目的。

            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>
                      ...
                   )
                }
            

            }

            【讨论】:

              【解决方案12】:

              您可以将状态值直接绑定到样式对象。这是一个例子:

              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>
               );
               }
              }
              

              【讨论】:

                【解决方案13】:

                例如,如果您正在使用带有过滤器的屏幕,并且您想设置过滤器的背景是否被选中,您可以这样做:

                <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 action,this.props.venueFilters是redux state。

                【讨论】:

                  【解决方案14】:

                  你可以这样做。

                  在您的组件中:

                  const getRandomColor = () => {
                    // you can use your component props here.
                  }
                  
                  <View style={[styles.jewelStyle, {backgroundColor: getRandomColor()}]} />
                  

                  使用样式表创建您的样式:

                  const styles = StyleSheet.create({
                    jewelStyle: {
                      backgroundColor: 'red',
                    },
                  });
                  

                  【讨论】:

                    【解决方案15】:
                    <View 
                     style={[styles.categoryItem,{marginTop: index <= numOfColumns-1 ? 10 : 0   }]}
                    >                                       
                    

                    【讨论】:

                      【解决方案16】:
                        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;
                      

                      【讨论】:

                        【解决方案17】:

                        万一有人需要申请条件

                         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
                               }
                            }
                        

                        【讨论】:

                          【解决方案18】:

                          这对我有用:

                          render() {
                            const { styleValue } = this.props;
                            const dynamicStyleUpdatedFromProps = {
                              height: styleValue,
                              width: styleValue,
                              borderRadius: styleValue,
                            }
                          
                            return (
                              <View style={{ ...styles.staticStyleCreatedFromStyleSheet, ...dynamicStyleUpdatedFromProps }} />
                            );
                          }
                          

                          出于某种原因,这是我正确更新的唯一方法。

                          【讨论】:

                            【解决方案19】:

                            您可以将样式组件用于本机反应,它会为您提供动态样式,就像用于 web 的情感或样式组件一样。

                            【讨论】:

                              【解决方案20】:

                              如果您遵循 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 样式表 并使用 React hook 模式将它们链接到功能组件。

                              -> Codesandbox

                              【讨论】:

                                猜你喜欢
                                • 2021-09-22
                                • 2019-01-20
                                • 2017-06-04
                                • 2019-07-17
                                • 1970-01-01
                                • 2018-10-20
                                • 1970-01-01
                                • 2020-06-04
                                • 1970-01-01
                                相关资源
                                最近更新 更多