web-dev-qa-db-fra.com

React Native: différents styles appliqués au changement d'orientation

Je développe une application React Native à déployer en tant qu'application native sur iOS et Android (et Windows, si possible).

Le problème est que nous voulons que la disposition soit différente selon les dimensions de l'écran et son orientation.

J'ai créé des fonctions qui renvoient l'objet styles et sont appelées sur la fonction de rendu de chaque composant, je suis donc en mesure d'appliquer différents styles au démarrage de l'application, mais si l'orientation (ou la taille de l'écran) change une fois l'application initialisée, elles ne sont ni recalculées ni réappliquées.

J'ai ajouté des écouteurs au rendu supérieur afin de mettre à jour son état lors du changement d'orientation (et cela force un rendu pour le reste de l'application), mais les sous-composants ne sont pas en cours de rendu (car, en fait, ils n'ont pas été modifiés ).

Donc, ma question est: comment puis-je créer des styles qui peuvent être complètement différents basé sur la taille et l'orientation de l'écran, tout comme avec les requêtes CSS média (qui sont rendues à la volée)?

J'ai déjà essayé react-native-responsive module sans chance.

Je vous remercie!

10
Unapedra

Enfin, j'ai pu le faire. Je ne connais pas les problèmes de performances qu'il peut entraîner, mais ils ne devraient pas être un problème car il ne s'agit que d'un redimensionnement ou d'un changement d'orientation.

J'ai créé un contrôleur global où j'ai une fonction qui reçoit le composant (le conteneur, la vue) et lui ajoute un écouteur d'événement:

const getScreenInfo = () => {
    const dim = Dimensions.get('window');
    return dim;
}    

const bindScreenDimensionsUpdate = (component) => {
    Dimensions.addEventListener('change', () => {
        try{
            component.setState({
                orientation: isPortrait() ? 'portrait' : 'landscape',
                screenWidth: getScreenInfo().width,
                screenHeight: getScreenInfo().height
            });
        }catch(e){
            // Fail silently
        }
    });
}

Avec cela, je force à restituer le composant quand il y a un changement d'orientation ou de redimensionnement de la fenêtre.

Ensuite, sur chaque constructeur de composant:

import ScreenMetrics from './globalFunctionContainer';

export default class UserList extends Component {
  constructor(props){
    super(props);

    this.state = {};

    ScreenMetrics.bindScreenDimensionsUpdate(this);
  }
}

De cette façon, il est rendu à chaque fois qu'il y a un redimensionnement de la fenêtre ou un changement d'orientation.

Vous devriez noter, cependant, que cela doit être appliqué à chaque composant que nous voulons écouter les changements d'orientation, car si le conteneur parent est mis à jour mais le state (ou props) des enfants ne sont pas mis à jour, ils ne seront pas restitués, donc cela peut être une perte de performance si nous avons un grand arbre pour les enfants.

J'espère que cela aide quelqu'un!

3
Unapedra

La solution peut être trouvée [ici] [1].

L'orientation des applications du portrait au paysage et vice versa est une tâche qui semble facile mais peut être délicate à réagir en natif lorsque la vue doit être modifiée lorsque l'orientation change. En d'autres termes, avoir des vues différentes définies pour les deux orientations peut être obtenu en considérant ces deux étapes.

Importer des dimensions depuis React Native

import { Dimensions } from 'react-native';

Pour identifier l'orientation actuelle et rendre la vue en conséquence

/**
 * Returns true if the screen is in portrait mode
 */
const isPortrait = () => {
    const dim = Dimensions.get('screen');
    return dim.height >= dim.width;
};

/**
 * Returns true of the screen is in landscape mode
 */
const isLandscape = () => {
    const dim = Dimensions.get('screen');
    return dim.width >= dim.height;
};

Pour savoir quand l'orientation change pour changer de vue en conséquence

// Event Listener for orientation changes
    Dimensions.addEventListener('change', () => {
        this.setState({
            orientation: Platform.isPortrait() ? 'portrait' : 'landscape'
        });
    });

Assemblage de toutes les pièces

import React from 'react';
import {
  StyleSheet,
  Text,
  Dimensions,
  View
} from 'react-native';

export default class App extends React.Component {
  constructor() {
    super();

    /**
    * Returns true if the screen is in portrait mode
    */
    const isPortrait = () => {
      const dim = Dimensions.get('screen');
      return dim.height >= dim.width;
    };

    this.state = {
      orientation: isPortrait() ? 'portrait' : 'landscape'
    };

    // Event Listener for orientation changes
    Dimensions.addEventListener('change', () => {
      this.setState({
        orientation: isPortrait() ? 'portrait' : 'landscape'
      });
    });

  }

  render() {
    if (this.state.orientation === 'portrait') {
      return (
          //Render View to be displayed in portrait mode
       );
    }
    else {
      return (
        //Render View to be displayed in landscape mode
      );
    }

  }
}

Comme l'événement défini pour regarder le changement d'orientation utilise cette commande 'this.setState ()', cette méthode appelle automatiquement à nouveau 'render ()' so we don ' t avoir à se soucier de le rendre à nouveau, tout est pris en charge.

19
Mridul Tripathi

Vous pouvez utiliser le prop onLayout:

export default class Test extends Component {

  constructor(props) {
    super(props);
    this.state = {
      screen: Dimensions.get('window'),
    };
  }

  getOrientation(){
    if (this.state.screen.width > this.state.screen.height) {
      return 'LANDSCAPE';
    }else {
      return 'PORTRAIT';
    }
  }

  getStyle(){
    if (this.getOrientation() === 'LANDSCAPE') {
      return landscapeStyles;
    } else {
      return portraitStyles;
    }
  }
  onLayout(){
    this.setState({screen: Dimensions.get('window')});
  }

  render() {
    return (
      <View style={this.getStyle().container} onLayout = {this.onLayout.bind(this)}>

      </View>
      );
    }
  }
}

const portraitStyles = StyleSheet.create({
 ...
});

const landscapeStyles = StyleSheet.create({
  ...
});
9
Adrian

J'ai, de loin, eu le plus de succès avec cette bibliothèque: https://github.com/axilis/react-native-responsive-layout Il fait ce que vous demandez et bien plus encore. Implémentation simple des composants sans presque aucune logique comme certaines des réponses les plus complexes ci-dessus. Mon projet utilise le téléphone, la tablette et le Web via RNW - et la mise en œuvre est sans faille. De plus, lors du redimensionnement du navigateur, il est vraiment réactif, et pas seulement lors du rendu initial - la gestion de l'orientation du téléphone change parfaitement.

Exemple de code (Mettez tous les composants comme enfants de blocs):

<Grid>
  <Section> {/* Light blue */}
    <Block xsSize="1/1" smSize="1/2" />
    <Block xsSize="1/1" smSize="1/2" />
    <Block xsSize="1/1" smSize="1/2" /> 
  </Section>
  <Section> {/* Dark blue */}
    <Block size="1/1" smSize="1/2" />
    <Block size="1/1" smSize="1/2" />
    <Block size="1/1" smSize="1/2" />
    <Block size="1/1" smSize="1/2" />
    <Block size="1/1" smSize="1/2" />
  </Section>
</Grid>

Pour donner ceci:

enter image description here

0
Steven H