¿Puedo crear estilos dinámicos en React Native?

119

Digamos que tengo un componente con un render como este:

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

Donde jewelStyle =

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

¿Cómo puedo hacer que el color de fondo sea dinámico y asignado aleatoriamente? He intentado

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

Pero esto hace que todas las instancias de View tengan el mismo color, quiero que cada una sea única.

¿Algun consejo?

Pete Thorne
fuente

Respuestas:

176

Normalmente hago algo como:

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

...

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

Cada vez que se renderiza la Vista, se creará una instancia de un nuevo objeto de estilo con un color aleatorio asociado. Por supuesto, esto significa que los colores cambiarán cada vez que se vuelva a renderizar el componente, lo que quizás no sea lo que desea. En su lugar, podría hacer algo como esto:

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

...

jewelStyle = function(myColor) {
   return {
     borderRadius: 10,
     background: myColor,
   }
 }
Jimmie Berg
fuente
32
Este método no usa hojas de estilo en absoluto. ¿Cuál es el propósito de aquellos que declaran las hojas de estilo de Stylesheet.create()todos modos?
fatuhoku
2
@fatuhoku es bueno para cuando necesitas reutilizar el mismo estilo en varios lugares
Bob9630
4
¿Existe una gran ventaja de rendimiento al usar Stylesheet.create?
Domingo
35
@DominicTobias Stylesheet.crear paquetes y "enviar" el estilo a la zona nativa solo una vez. Lo que significa que cuando reutiliza el mismo estilo varias veces, o carga el mismo componente varias veces, reutiliza el estilo en lugar de empaquetar y "enviar" nuevamente. Por ejemplo, si está cargando 3000 filas con estilo, sentirá un aumento considerable en el rendimiento.
sospedra
64

Sí, puede y, de hecho, debe usar StyleSheet.createpara crear sus 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;

Y entonces:

<Header title="HOME" style={ {backgroundColor: '#10f1f0'} } />
diegoprates
fuente
9
Esta respuesta muestra un buen ejemplo en el que un estilo se define en la hoja de estilo, pero se puede anular más adelante en un componente
bits y
5
AFAIK usando StyleSheet.flattensimplemente descarta cualquier optimización de StyleSheet.createcomo se indica en los documentos: "NOTA: Tenga cuidado, ya que abusar de esto puede gravarlo en términos de optimizaciones. Los ID habilitan optimizaciones a través del puente y la memoria en general. Referirse a objetos de estilo directamente lo privará de estas optimizaciones ". ( facebook.github.io/react-native/docs/stylesheet.html ).
gustavopch
27

Si aún desea aprovechar StyleSheet.createy también tener estilos dinámicos, pruebe esto:

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 cómo la stylepropiedad de Viewse establece como una matriz que combina su hoja de estilo con sus estilos dinámicos.

Carlos Atencio
fuente
11

El mas facil es el mio:

<TextInput
  style={[
    styles.default,
    this.props.singleSourceOfTruth ?
    { backgroundColor: 'black' } 
    : { backgroundColor: 'white' }
]}/>
Lloviendo
fuente
Edité la respuesta publicada para cumplir con el comentario de
@Sarahcartenz
maravilloso, de hecho es genial. También se puede anular una propiedad con esta solución, ¿verdad? la última anula la anterior
saldrá el
10

Tuve algún problema sintáctico. Esto funcionó para mi

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

const styles = StyleSheet.create({
   textStyle :{
      textAlign: 'center',   
      fontFamily: 'Arial',
      fontSize: 16
  }
  });
Yogesh Lolusare
fuente
Gracias @Yogesh, esto es exactamente lo que estoy buscando. Quiero hacer uso de estilos y, sin embargo, poder agregar más en las cosas que necesito.
TLee
4

Querrás algo como esto:

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

    }
});

En este ejemplo, tomo la matriz de filas, que contiene los datos de las filas del componente, y la mapeo en una matriz de componentes de texto. Utilizo estilos en línea para llamar a la getRandomColorfunción cada vez que creo un nuevo componente de texto.

El problema con su código es que define el estilo una vez y, por lo tanto, getRandomColor solo se llama una vez, cuando define el estilo.

Colin Ramsay
fuente
Hola Colin, gracias por eso, pero ¿cómo puedo pasar los otros parámetros de estilo al mismo tiempo?
Pete Thorne
¿Te refieres a style = {{backgroundColor: getRandomColor (), color: 'black'}}?
Colin Ramsay
Gracias, eso funcionará, pero he aceptado la otra respuesta, ya que ayuda a mostrar cómo puede pasar un bloque de estilos de una vez.
Pete Thorne
2
De hecho, creo que la otra respuesta también fue la mejor :)
Colin Ramsay
2

Sé que es muy tarde, pero para cualquiera que todavía se lo pregunte, aquí hay una solución fácil.

Podrías simplemente hacer una matriz para los estilos:

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

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

El segundo anulará cualquier color de fondo original como se indica en la hoja de estilo. Luego tenga una función que cambie el color:

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

Esto generará un color hexadecimal aleatorio. Luego simplemente llame a esa función cuando sea y bam, nuevo color de fondo.

Max Gertner
fuente
1

Sé que hay varias respuestas, pero creo que la mejor y más simple es usar un estado "Cambiar" es el propósito del 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
fuente
1

Puede vincular el valor de estado directamente al objeto de estilo. Aquí hay un ejemplo:

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
fuente
1

Sí, puedes crear estilos dinámicos. Puede pasar valores de Componentes.

Primero crea 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,
      }
    })
  }
}

luego úselo en su componente de la siguiente manera

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
fuente
1

El uso del operador de extensión de objetos "..." funcionó para mí:

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

Si está utilizando una pantalla con filtros, por ejemplo, y desea establecer el fondo del filtro con respecto a si se seleccionó o no, puede hacer:

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

En qué filtro de conjunto está:

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

PD: la función this.props.setVenueFilter(filters)es una acción de reducción y this.props.venueFilterses un estado de reducción.

FrikLima
fuente
0

En caso de que alguien necesite aplicar condiciones

 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
fuente
0

Esto es lo que funcionó para mí:

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

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

Por alguna razón, esta era la única forma en que la mía se actualizaría correctamente.

Daltron
fuente