Obtenir la taille d'une vue dans React Native

147

Est-il possible d'obtenir la taille (largeur et hauteur) d'une certaine vue? Par exemple, j'ai une vue montrant la progression:

<View ref='progressBar' style={{backgroundColor:'red',flex:this.state.progress}} /> 

J'ai besoin de connaître la largeur réelle de la vue pour aligner correctement les autres vues. Est-ce possible?

Matthieu
la source

Réponses:

315

Depuis React Native 0.4.2, les composants View ont un onLayoutaccessoire . Transmettez une fonction qui prend un objet événement. L'événement nativeEventcontient la disposition de la vue.

<View onLayout={(event) => {
  var {x, y, width, height} = event.nativeEvent.layout;
}} />

Le onLayoutgestionnaire sera également appelé chaque fois que la vue est redimensionnée.

Le principal inconvénient est que le onLayoutgestionnaire est d'abord appelé une image après le montage de votre composant, vous pouvez donc masquer votre interface utilisateur jusqu'à ce que vous ayez calculé votre disposition.

ide
la source
2
Le problème de cette approche est que lorsque l'appareil pivote / que la taille de la vue change, je ne suis pas appelé à nouveau onLayout.
Matthieu
4
onLayout est appelé lorsque le cadre de la vue change. Peut-être que votre vue ne change pas sa taille ou sa position lors de la rotation. Regardez l'exemple onLayout dans UIExplorer, où onLayout est appelé lors de la rotation.
ide
2
Disons que je veux afficher un Viewdifféremment en fonction des dimensions. Je ne comprends pas comment je peux utiliser la onLayoutfonction de vue pour changer la façon dont j'affiche la vue. Cela ne mène-t-il pas à une boucle infinie?
Lane Rettig le
2
@LaneRettig Oui, c'est le cas si c'est vraiment ce que vous voulez faire, alors vous devriez écrire votre code de manière à atteindre l'équilibre statique. Mais il semble que vous souhaitiez peut-être simplement personnaliser votre vue en fonction des dimensions de l'écran, auquel cas cela onLayoutn'a aucun rapport.
ide
7
@ide comment cacheriez-vous l'interface utilisateur jusqu'à ce que la mise en page soit calculée?
Irfanlone
27

C'est la seule chose qui a fonctionné pour moi:

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  Image
} from 'react-native';

export default class Comp extends Component {

  find_dimesions(layout){
    const {x, y, width, height} = layout;
    console.warn(x);
    console.warn(y);
    console.warn(width);
    console.warn(height);
  }
  render() {
    return (
      <View onLayout={(event) => { this.find_dimesions(event.nativeEvent.layout) }} style={styles.container}>
        <Text style={styles.welcome}>
          Welcome to React Native!
        </Text>
        <Text style={styles.instructions}>
          To get started, edit index.android.js
        </Text>
        <Text style={styles.instructions}>
          Double tap R on your keyboard to reload,{'\n'}
          Shake or press menu button for dev menu
        </Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5,
  },
});

AppRegistry.registerComponent('Comp', () => Comp);
Abhishek Kumar
la source
14

Fondamentalement, si vous souhaitez définir la taille et la modifier, définissez-la comme suit sur la mise en page:

import React, { Component } from 'react';
import { AppRegistry, StyleSheet, View } from 'react-native';

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'yellow',
  },
  View1: {
    flex: 2,
    margin: 10,
    backgroundColor: 'red',
    elevation: 1,
  },
  View2: {
    position: 'absolute',
    backgroundColor: 'orange',
    zIndex: 3,
    elevation: 3,
  },
  View3: {
    flex: 3,
    backgroundColor: 'green',
    elevation: 2,
  },
  Text: {
    fontSize: 25,
    margin: 20,
    color: 'white',
  },
});

class Example extends Component {

  constructor(props) {
    super(props);

    this.state = {
      view2LayoutProps: {
        left: 0,
        top: 0,
        width: 50,
        height: 50,
      }
    };
  }

  onLayout(event) {
    const {x, y, height, width} = event.nativeEvent.layout;
    const newHeight = this.state.view2LayoutProps.height + 1;
    const newLayout = {
        height: newHeight ,
        width: width,
        left: x,
        top: y,
      };

    this.setState({ view2LayoutProps: newLayout });
  }

  render() {
    return (
      <View style={styles.container}>
        <View style={styles.View1}>
          <Text>{this.state.view2LayoutProps.height}</Text>
        </View>
        <View onLayout={(event) => this.onLayout(event)} 
              style={[styles.View2, this.state.view2LayoutProps]} />
        <View style={styles.View3} />
      </View>
    );
  }

}


AppRegistry.registerComponent(Example);

Vous pouvez créer beaucoup plus de variations de la façon dont il doit être modifié, en utilisant ceci dans un autre composant qui a une autre vue comme wrapper et créer un rappel onResponderRelease, qui pourrait passer l'emplacement de l'événement tactile dans l'état, qui pourrait ensuite être passé au composant enfant en tant que propriété, qui pourrait remplacer l'état mis à jour de onLayout, en plaçant {[styles.View2, this.state.view2LayoutProps, this.props.touchEventTopLeft]}et ainsi de suite.

juslintek
la source
11

Vous pouvez directement utiliser le Dimensionsmodule et calculer la taille de vos vues. En fait, Dimensionsdonnez-vous les principales tailles de fenêtre.

import { Dimensions } from 'Dimensions';

Dimensions.get('window').height;
Dimensions.get('window').width;

J'espère vous aider!

Mise à jour : Aujourd'hui, l'utilisation de la configuration native StyleSheetavec Flex sur vos vues aide à écrire du code propre avec des solutions de mise en page élégantes dans des cas larges au lieu de calculer vos tailles de vue ...

Bien que la création de composants de grille personnalisés , qui répondent aux événements de redimensionnement de la fenêtre principale, puisse produire une bonne solution dans de simples composants de widget

Bruno Guerra
la source
3
Gah, pourquoi n'est-ce pas documenté plus clairement!?! J'essayais 'width' et 'height' au lieu de ('window'). Width etc.
272
L'exemple que vous avez donné fournit les dimensions de la fenêtre , pas d'une vue donnée; comment est-ce pertinent?
Mark Amery
1
@MarkAmery avec les dimensions de la fenêtre, vous pouvez planifier à quoi ressembleront vos vues
Bruno Guerra
2
@BrunoGuerra pouvez-vous afficher le code pour obtenir une certaine taille de vue (pas de fenêtre) par Dimensions?
Spark.Bao
4
Les dimensions ne sont pas mises à jour sur de nombreux appareils lorsque l'appareil est tourné. Il s'agit d'un problème connu et ne semble pas être résolu à partir de react-native 0.32.0-rc.0
Glenn Lawrence
10

Peut-être que vous pouvez utiliser measure:

measureProgressBar() {
    this.refs.welcome.measure(this.logProgressBarLayout);
},

logProgressBarLayout(ox, oy, width, height, px, py) {
  console.log("ox: " + ox);
  console.log("oy: " + oy);
  console.log("width: " + width);
  console.log("height: " + height);
  console.log("px: " + px);
  console.log("py: " + py);
}
Yinfeng
la source
Pour la vie de moi, je ne peux pas comprendre comment utiliser correctement NativeMethodsMixin. Peu importe ce que je fais, measurec'est toujours indéfini. Des pointeurs?
chandlervdw
2
Vous n'avez pas besoin d'utiliser NativeMethodsMixinla fonction n'est disponible que sur certains éléments. Par exemple, TouchableWithFeedbacka la fonction de mesure, mais pas un régulier Touchable. Essayez de changer le type que Viewvous utilisez, obtenez la référence et vérifiez si l'élément de mesure est disponible. J'ai trébuché là-dessus aussi.
n0rm
-3

pour moi, définir les dimensions pour utiliser% est ce qui a fonctionné pour moi width:'100%'

pinchez254
la source
-4

Voici le code pour obtenir les dimensions de la vue complète de l'appareil.

var windowSize = Dimensions.get("window");

Utilisez-le comme ceci:

width=windowSize.width,heigth=windowSize.width/0.565

ravi
la source
C'est correct, mais cela ne répond pas à la question.
Moso Akinyemi