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?

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

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

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.


11

Najłatwiejszy jest mój:

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

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

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.


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.


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

}


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

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

1

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

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

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.


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

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ć.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.