Czy mogę tworzyć dynamiczne style w React Native?

119

Powiedzmy, że mam komponent z takim renderowaniem:

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

Gdzie jewelStyle =

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

Jak mogę ustawić dynamiczny i losowy kolor tła? próbowałem

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

Ale to sprawia, że ​​wszystkie wystąpienia View mają ten sam kolor, chcę, aby każdy był wyjątkowy.

Jakieś wskazówki?

Pete Thorne
źródło

Odpowiedzi:

176

Zwykle robię coś w stylu:

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

...

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

Za każdym razem, gdy View jest renderowany, zostanie utworzony wystąpienie nowego obiektu stylu z przypisanym losowym kolorem. Oczywiście oznacza to, że kolory będą się zmieniać za każdym razem, gdy komponent zostanie ponownie renderowany, co prawdopodobnie nie jest tym, czego chcesz. Zamiast tego możesz zrobić coś takiego:

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

...

jewelStyle = function(myColor) {
   return {
     borderRadius: 10,
     background: myColor,
   }
 }
Jimmie Berg
źródło
32
Ta metoda w ogóle nie używa arkuszy stylów. Jaki jest cel tych deklaracji arkuszy stylów Stylesheet.create()?
fatuhoku
2
@fatuhoku jest miło, gdy musisz ponownie użyć tego samego stylu w wielu miejscach
Bob9630,
4
czy używanie Stylesheet.create daje wiele korzyści?
Dominic
35
@DominicTobias Stylesheet.Twórz paczki i tylko raz „wyślij” styl do strefy natywnej. Co oznacza, że ​​gdy wielokrotnie używasz tego samego stylu lub ładujesz ten sam komponent wiele razy, styl ten zostanie użyty ponownie, zamiast pakować i ponownie „wysyłać”. Na przykład, jeśli ładujesz 3000 stylowych rzędów, poczujesz znaczny wzrost wydajności.
sospedra
64

Tak, możesz i właściwie powinieneś używać go StyleSheet.createdo tworzenia swoich stylów.

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;

I wtedy:

<Header title="HOME" style={ {backgroundColor: '#10f1f0'} } />
diegoprates
źródło
9
Ta odpowiedź pokazuje dobry przykład, w którym styl jest zdefiniowany w arkuszu stylów, ale można go później
nadpisać
5
AFAIK użycie StyleSheet.flattenpo prostu odrzuca wszelką optymalizację, StyleSheet.createjak podano w dokumentach: „UWAGA: Zachowaj ostrożność, ponieważ nadużywanie tego może obciążyć Cię w zakresie optymalizacji. Identyfikatory umożliwiają optymalizacje przez most i ogólnie pamięć. Bezpośrednie odwoływanie się do stylów obiektów pozbawi Cię te optymalizacje ”. ( facebook.github.io/react-native/docs/stylesheet.html ).
gustavopch
27

Jeśli nadal chcesz korzystać z StyleSheet.createdynamicznych stylów, a także je mieć, wypróbuj to:

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

Zwróć uwagę, że stylewłaściwość elementu Viewjest ustawiona jako tablica, która łączy Twój arkusz stylów ze stylami dynamicznymi.

Carlos Atencio
źródło
11

Najłatwiejszy jest mój:

<TextInput
  style={[
    styles.default,
    this.props.singleSourceOfTruth ?
    { backgroundColor: 'black' } 
    : { backgroundColor: 'white' }
]}/>
Pada
źródło
Zredagowałem opublikowaną odpowiedź, aby zachować zgodność z komentarzem
@Sarahcartenz
cudowne, naprawdę świetne. Takim rozwiązaniem można też nadpisać właściwość, prawda? ostatnia zastępuje poprzednią
besil
10

Miałem jakiś problem syntaktycznie. To zadziałało dla mnie

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

const styles = StyleSheet.create({
   textStyle :{
      textAlign: 'center',   
      fontFamily: 'Arial',
      fontSize: 16
  }
  });
Yogesh Lolusare
źródło
Dziękuję @Yogesh, właśnie tego szukam. Chcę korzystać ze stylów, a mimo to móc dodawać do nich więcej rzeczy, których potrzebowałem.
TLee
4

Będziesz chciał coś takiego:

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

    }
});

W tym przykładzie biorę tablicę wierszy, zawierającą dane dla wierszy w komponencie i mapuję ją na tablicę komponentów Text. Używam stylów wbudowanych do wywoływania getRandomColorfunkcji za każdym razem, gdy tworzę nowy komponent Text.

Problem z twoim kodem polega na tym, że definiujesz styl raz i dlatego getRandomColor jest wywoływany tylko raz - kiedy definiujesz styl.

Colin Ramsay
źródło
Cześć Colin, dzięki za to, ale jak mogę jednocześnie przekazać inne parametry stylu?
Pete Thorne
Masz na myśli style = {{backgroundColor: getRandomColor (), color: 'black'}}?
Colin Ramsay
Dzięki, to zadziała, ale zaakceptowałem drugą odpowiedź, ponieważ pomaga ona pokazać, jak możesz przejść przez blok stylów za jednym razem.
Pete Thorne
2
Właściwie myślę, że druga odpowiedź też była lepsza :)
Colin Ramsay
2

Wiem, że jest bardzo późno, ale dla każdego, kto wciąż się zastanawia, jest proste rozwiązanie.

Możesz po prostu stworzyć tablicę dla stylów:

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

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

Drugi zastąpi oryginalny kolor tła, zgodnie z opisem w arkuszu stylów. Następnie użyj funkcji, która zmienia kolor:

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

Spowoduje to wygenerowanie losowego koloru szesnastkowego. Następnie po prostu wywołaj tę funkcję kiedykolwiek i bach, nowy kolor tła.

Max Gertner
źródło
1

Wiem, że istnieje kilka odpowiedzi, ale myślę, że najlepszym i najprostszym jest użycie stanu „Zmieniać” jest celem stanu.

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
źródło
1

Wartość stanu można powiązać bezpośrednio z obiektem stylu. Oto przykład:

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
źródło
1

Tak, możesz tworzyć dynamiczne style. Możesz przekazywać wartości z komponentów.

Najpierw utwórz 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,
      }
    })
  }
}

następnie użyj go w swoim komponencie w następujący sposób

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
źródło
1

Użycie operatora rozprzestrzeniania obiektów "..." zadziałało dla mnie:

<View style={{...jewelStyle, ...{'backgroundColor': getRandomColor()}}}></View>
Cem Roso
źródło
0

Jeśli korzystasz na przykład z ekranu z filtrami i chcesz ustawić tło filtru dotyczące tego, czy został wybrany, czy nie, możesz:

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

Na którym zestawie znajduje się filtr:

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: funkcja this.props.setVenueFilter(filters)jest działaniem reduks i this.props.venueFiltersjest stanem reduks.

FrikLima
źródło
0

Na wypadek, gdyby ktoś musiał zastosować warunki

 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
źródło
0

Oto, co zadziałało dla mnie:

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

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

Z jakiegoś powodu był to jedyny sposób, w jaki mój mógł się poprawnie zaktualizować.

Daltron
źródło