Posso criar estilos dinâmicos no React Native?

119

Digamos que eu tenha um componente com renderização assim:

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

Onde jewelStyle =

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

Como posso tornar a cor de fundo dinâmica e atribuída aleatoriamente? eu tentei

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

Mas isso faz com que todas as instâncias de View tenham a mesma cor, quero que cada uma seja única.

Alguma dica?

Pete Thorne
fonte

Respostas:

176

Normalmente faço algo parecido com:

<View style={this.jewelStyle()} />

...

jewelStyle = function(options) {
   return {
     borderRadius: 12,
     background: randomColor(),
   }
 }

Cada vez que View é renderizado, um novo objeto de estilo será instanciado com uma cor aleatória associada a ele. Claro, isso significa que as cores mudarão sempre que o componente for refeito, o que talvez não seja o que você deseja. Em vez disso, você poderia fazer algo assim:

var myColor = randomColor()
<View style={jewelStyle(myColor)} />

...

jewelStyle = function(myColor) {
   return {
     borderRadius: 10,
     background: myColor,
   }
 }
Jimmie Berg
fonte
32
Este método não usa folhas de estilo. Qual é a finalidade dessas folhas de estilo declaradas Stylesheet.create()?
fatuhoku
2
@fatuhoku é bom para quando você precisa reutilizar o mesmo estilo em vários lugares
Bob9630
4
Há muitos benefícios de desempenho em usar Stylesheet.create?
Dominic
35
@DominicTobias Stylesheet.create packs e "envia" o estilo para a zona nativa apenas uma vez. O que significa que quando você reutiliza o mesmo estilo várias vezes ou carrega o mesmo componente várias vezes, ele reutiliza o estilo em vez de empacotar e "enviar" novamente. Por exemplo, se você estiver carregando 3.000 linhas estilizadas, você sentirá um aumento considerável no desempenho.
sospedra
64

Sim, você pode e, na verdade, deve usar StyleSheet.createpara criar seus estilos.

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;

E depois:

<Header title="HOME" style={ {backgroundColor: '#10f1f0'} } />
diegopratos
fonte
9
Esta resposta mostra um bom exemplo em que um estilo é definido na folha de estilo, mas pode ser substituído posteriormente em um componente
bits e
5
O uso do AFAIK StyleSheet.flattensimplesmente descarta qualquer otimização StyleSheet.createconforme declarado nos documentos: "NOTA: Tenha cuidado, pois abusar disso pode sobrecarregar você em termos de otimizações. Os IDs permitem otimizações por meio da ponte e da memória em geral. Consultar diretamente os objetos de estilo o privará de essas otimizações. " ( facebook.github.io/react-native/docs/stylesheet.html ).
gustavopch de
27

Se você ainda deseja aproveitar as vantagens StyleSheet.createe também ter estilos dinâmicos, experimente:

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

Observe como a stylepropriedade de Viewé definida como uma matriz que combina sua folha de estilo com seus estilos dinâmicos.

Carlos Atencio
fonte
11

O mais fácil é o meu:

<TextInput
  style={[
    styles.default,
    this.props.singleSourceOfTruth ?
    { backgroundColor: 'black' } 
    : { backgroundColor: 'white' }
]}/>
Chovendo
fonte
Editei a resposta postada em conformidade com o comentário de
@Sarahcartenz
maravilhoso, é realmente ótimo. Também é possível substituir uma propriedade com esta solução, certo? o último substitui o anterior
antes de
10

Teve algum problema sintaticamente. Isso funcionou para mim

<Text style={[styles.textStyle,{color: 'red'}]}> Hello </Text>

const styles = StyleSheet.create({
   textStyle :{
      textAlign: 'center',   
      fontFamily: 'Arial',
      fontSize: 16
  }
  });
Yogesh Lolusare
fonte
Obrigado @Yogesh, isso é exatamente o que estou procurando. Eu quero fazer uso de estilos e ainda ser capaz de adicionar mais coisas que eu preciso.
TLee
4

Você vai querer algo assim:

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

    }
});

Neste exemplo, pego a matriz de linhas, contendo os dados das linhas do componente, e mapeio-a em uma matriz de componentes de texto. Eu uso estilos embutidos para chamar ogetRandomColor função sempre que crio um novo componente de texto.

O problema com seu código é que você define o estilo uma vez e, portanto, getRandomColor só é chamado uma vez - quando você define o estilo.

Colin Ramsay
fonte
Oi Colin, obrigado por isso, mas como posso passar os outros parâmetros de estilo ao mesmo tempo?
Pete Thorne
Você quer dizer como style = {{backgroundColor: getRandomColor (), color: 'black'}}?
Colin Ramsay
Obrigado, isso vai funcionar, mas aceitei a outra resposta porque ajuda a mostrar como você pode passar um bloco de estilos de uma vez.
Pete Thorne
2
Na verdade, acho que a outra resposta foi a melhor também :)
Colin Ramsay
2

Eu sei que é extremamente tarde, mas para quem ainda está se perguntando aqui está uma solução fácil.

Você pode simplesmente fazer uma matriz para os estilos:

this.state ={
   color: "#fff"
}

style={[
  styles.jewelstyle, {
  backgroundColor: this.state.BGcolor
}

O segundo substituirá qualquer cor de fundo original conforme declarado na folha de estilo. Então, tenha uma função que muda a cor:

generateNewColor(){
  var randomColor = '#'+Math.floor(Math.random()*16777215).toString(16);
  this.setState({BGcolor: randomColor})
}

Isso irá gerar uma cor hexadecimal aleatória. Em seguida, basta chamar essa função quando quiser e bam, nova cor de fundo.

Max Gertner
fonte
1

Eu sei que existem várias respostas, mas acho que a melhor e mais simples é usar um estado "Mudar" é o propósito do estado.

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

}

Cesar alonso
fonte
1

Você pode vincular o valor do estado diretamente ao objeto de estilo. Aqui está um exemplo:

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>
 );
 }
}
Hossam Ghareeb
fonte
1

Sim, você pode criar estilos dinâmicos. Você pode passar valores de Componentes.

Primeiro crie 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,
      }
    })
  }
}

em seguida, use-o em seu componente da seguinte maneira

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>
    );
  }
}
Rajesh Nasit
fonte
1

Usar o operador de propagação de objeto "..." funcionou para mim:

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

Se você estiver usando uma tela com filtros, por exemplo, e quiser definir o fundo do filtro se ele foi selecionado ou não, você pode fazer:

<TouchableOpacity style={this.props.venueFilters.includes('Bar')?styles.filterBtnActive:styles.filterBtn} onPress={()=>this.setFilter('Bar')}>
<Text numberOfLines={1}>
Bar
</Text>
</TouchableOpacity>

Em qual filtro definido é:

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: a função this.props.setVenueFilter(filters)é uma ação redux e this.props.venueFiltersé um estado redux.

FrikLima
fonte
0

Caso alguém precise aplicar condições

 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
       }
    }
shankey
fonte
0

Aqui está o que funcionou para mim:

render() {
  const { styleValue } = this.props;
  const dynamicStyleUpdatedFromProps = {
    height: styleValue,
    width: styleValue,
    borderRadius: styleValue,
  }

  return (
    <View style={{ ...styles.staticStyleCreatedFromStyleSheet, ...dynamicStyleUpdatedFromProps }} />
  );
}

Por algum motivo, essa era a única maneira de o meu ser atualizado corretamente.

Daltron
fonte