Posso creare stili dinamici in React Native?


119

Diciamo che ho un componente con un rendering come questo:

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

Dove jewelStyle =

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

Come posso rendere il colore di sfondo dinamico e assegnato in modo casuale? ho provato

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

Ma questo fa sì che tutte le istanze di View abbiano lo stesso colore, voglio che ognuna sia unica.

Qualche consiglio?

Risposte:


176

Di solito faccio qualcosa sulla falsariga di:

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

...

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

Ogni volta che viene eseguito il rendering di View, verrà creata un'istanza di un nuovo oggetto di stile con un colore casuale ad esso associato. Ovviamente, questo significa che i colori cambieranno ogni volta che il componente viene nuovamente renderizzato, il che forse non è quello che desideri. Invece, potresti fare qualcosa del genere:

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

...

jewelStyle = function(myColor) {
   return {
     borderRadius: 10,
     background: myColor,
   }
 }

32
Questo metodo non utilizza affatto i fogli di stile. Qual è lo scopo di coloro che dichiarano i fogli di stile Stylesheet.create()comunque?
fatuhoku

2
@fatuhoku è utile quando è necessario riutilizzare lo stesso stile in più posti
Bob9630

4
c'è molto di un vantaggio in termini di prestazioni nell'usare Stylesheet.create?
Dominic

36
@DominicTobias Stylesheet.create i pacchetti e "invia" lo stile alla zona nativa solo una volta. Ciò significa che quando riutilizzi lo stesso stile più volte o carichi lo stesso componente più volte, lo stile verrà riutilizzato invece di comprimere e "inviare" di nuovo. Ad esempio, se stai caricando 3000 righe in stile, sentirai un notevole aumento delle prestazioni.
sospedra

64

Sì, puoi e in realtà dovresti usare StyleSheet.createper creare i tuoi stili.

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 poi:

<Header title="HOME" style={ {backgroundColor: '#10f1f0'} } />

9
Questa risposta mostra un buon esempio in cui uno stile è definito nel foglio di stile, ma può essere sovrascritto in seguito in un componente
bitsand

5
Per quanto ne so, l'utilizzo StyleSheet.flattenelimina qualsiasi ottimizzazione da StyleSheet.createcome indicato nei documenti: "NOTA: prestare attenzione poiché un abuso di questo può tassare in termini di ottimizzazioni. Gli ID consentono le ottimizzazioni tramite il bridge e la memoria in generale. Fare riferimento direttamente agli oggetti di stile ti priverà di queste ottimizzazioni. " ( facebook.github.io/react-native/docs/stylesheet.html ).
gustavopch

27

Se vuoi comunque sfruttare StyleSheet.createe avere anche stili dinamici, prova questo:

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

Nota come la styleproprietà di Viewè impostata come un array che combina il tuo foglio di stile con i tuoi stili dinamici.


11

Il più semplice è il mio:

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

Ho modificato la risposta pubblicata per rispettare il commento di
@Sarahcartenz

meraviglioso, è davvero fantastico. Si può anche sostituire una proprietà con questa soluzione, giusto? l'ultimo sostituisce il precedente
besil

10

Ha avuto qualche problema sintatticamente. Questo ha funzionato per me

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

const styles = StyleSheet.create({
   textStyle :{
      textAlign: 'center',   
      fontFamily: 'Arial',
      fontSize: 16
  }
  });

Grazie @Yogesh, questo è esattamente quello che sto cercando. Voglio usare gli stili e tuttavia essere in grado di aggiungerne di più alle cose di cui avevo bisogno.
Venerdì

4

Avrai bisogno di qualcosa di simile:

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

    }
});

In questo esempio prendo l'array di righe, contenente i dati per le righe nel componente, e lo associo a un array di componenti di testo. Uso gli stili inline per chiamare la getRandomColorfunzione ogni volta che creo un nuovo componente Text.

Il problema con il tuo codice è che definisci lo stile una volta e quindi getRandomColor viene chiamato solo una volta, quando definisci lo stile.


Ciao Colin, grazie per questo, ma come posso passare contemporaneamente gli altri parametri di stile?
Pete Thorne

Intendi come style = {{backgroundColor: getRandomColor (), color: 'black'}}?
Colin Ramsay

Grazie, funzionerà ma ho accettato l'altra risposta in quanto aiuta a mostrare come puoi passare un blocco di stili in una volta sola.
Pete Thorne

2
In realtà penso che anche l'altra risposta sia stata la migliore :)
Colin Ramsay

2

So che è estremamente tardi, ma per chiunque se lo chieda, ecco una soluzione facile.

Potresti semplicemente creare un array per gli stili:

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

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

Il secondo sovrascriverà qualsiasi colore di sfondo originale come indicato nel foglio di stile. Quindi avere una funzione che cambia il colore:

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

Questo genererà un colore esadecimale casuale. Quindi chiama quella funzione ogni volta e bam, nuovo colore di sfondo.


1

So che ci sono molte risposte, ma penso che la migliore e più semplice sia usare uno stato "Cambiare" è lo scopo dello stato.

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

}


1

È possibile associare il valore di stato direttamente all'oggetto di stile. Ecco un esempio:

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

1

Sì, puoi creare stili dinamici. È possibile trasferire valori dai componenti.

Per prima cosa 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,
      }
    })
  }
}

quindi usalo nel tuo componente seguendo il modo

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

1

L'utilizzo dell'operatore di diffusione degli oggetti "..." ha funzionato per me:

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

0

Se ad esempio stai usando uno schermo con filtri e vuoi impostare lo sfondo del filtro riguardo se è stato selezionato o meno, puoi fare:

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

Su quale filtro impostato è:

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: la funzione this.props.setVenueFilter(filters)è un'azione redux ed this.props.venueFiltersè uno stato redux.


0

Nel caso qualcuno debba applicare le condizioni

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

0

Ecco cosa ha funzionato per me:

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

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

Per qualche ragione, questo era l'unico modo in cui il mio si aggiornava correttamente.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.