Obtener el tamaño de una vista en React Native

147

¿Es posible obtener el tamaño (ancho y alto) de una vista determinada? Por ejemplo, tengo una vista que muestra el progreso:

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

Necesito saber el ancho real de la vista para alinear otras vistas correctamente. es posible?

Mateo
fuente

Respuestas:

315

A partir de React Native 0.4.2, los componentes View tienen un onLayoutaccesorio . Pase una función que tome un objeto de evento. El evento nativeEventcontiene el diseño de la vista.

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

El onLayoutcontrolador también se invocará cada vez que se cambie el tamaño de la vista.

La advertencia principal es que el onLayoutcontrolador se invoca primero un cuadro después de que se haya montado su componente, por lo que es posible que desee ocultar su interfaz de usuario hasta que haya calculado su diseño.

ide
fuente
2
El problema de este enfoque es cuando el dispositivo gira / cambia el tamaño de la vista, no vuelvo a llamar a Layout.
Matthew
44
onLayout se invoca cuando cambia el marco de la vista. Quizás su vista no cambia su tamaño o posición en la rotación. Mire el ejemplo onLayout en el UIExplorer, donde onLayout se invoca en la rotación.
ide
2
Digamos que quiero mostrar un Viewdiferente de acuerdo con las dimensiones. No entiendo cómo puedo usar la onLayoutfunción de Vista para cambiar la forma en que visualizo la Vista. ¿Eso no conduce a un bucle infinito?
Lane Rettig
2
@LaneRettig Sí, si esto es realmente lo que quieres hacer, entonces debes escribir tu código de una manera que alcance el equilibrio estático. Pero parece que es posible que solo desee personalizar su vista en función de las dimensiones de la pantalla, en cuyo caso onLayoutno está relacionado.
ide
77
@ide ¿cómo escondería la interfaz de usuario hasta que se calcule el diseño?
Irfanlone
27

Esto es lo único que funcionó para mí:

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
fuente
14

Básicamente, si desea establecer el tamaño y hacer que cambie, configúrelo en un estado como este:

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

Puede crear muchas más variaciones de cómo debería modificarse, al usar esto en otro componente que tiene Otra vista como contenedor y crear una devolución de llamada onResponderRelease, que podría pasar la ubicación del evento táctil al estado, que luego podría pasar al componente secundario como propiedad, que podría anular el estado actualizado onLayout, colocando {[styles.View2, this.state.view2LayoutProps, this.props.touchEventTopLeft]}y así sucesivamente.

juslintek
fuente
11

Puede usar directamente el Dimensionsmódulo y calcular los tamaños de sus vistas. En realidad, le Dimensionsdan los tamaños de las ventanas principales.

import { Dimensions } from 'Dimensions';

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

Espero poder ayudarte!

Actualización : Hoy, usar nativo StyleSheetcon Flex organizando sus vistas ayuda a escribir código limpio con soluciones de diseño elegantes en casos amplios en lugar de calcular los tamaños de sus vistas ...

Si bien la creación de componentes de cuadrícula personalizados , que responden a los eventos de cambio de tamaño de la ventana principal, podría producir una buena solución en componentes de widget simples

Bruno Guerra
fuente
3
Gah, ¿por qué no se documenta esto más claramente?
272
El ejemplo que ha proporcionado proporciona las dimensiones de la ventana , no de una vista determinada; ¿Cómo es esto relevante?
Mark Amery
1
@MarkAmery con dimensiones de ventana que puede planificar cómo se verán sus vistas
Bruno Guerra
2
@BrunoGuerra, ¿puede mostrar el código para obtener un cierto tamaño de vista (no ventana) por Dimensiones?
Spark.Bao
44
Dimensiones no se actualiza en muchos dispositivos cuando se gira el dispositivo. Este es un problema conocido y no parece haberse solucionado a partir de react-native 0.32.0-rc.0
Glenn Lawrence
10

Quizás puedas usar 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
fuente
Por mi vida, no puedo entender cómo usarlo adecuadamente NativeMethodsMixin. No importa lo que haga, measuresiempre está indefinido. Cualquier puntero?
chandlervdw
2
No necesita usar NativeMethodsMixinla función solo está disponible en algunos elementos. Por ejemplo TouchableWithFeedback, tiene la función de medida, pero una regular Touchableno. Intente cambiar el tipo Viewque está utilizando, obtenga la referencia y verifique si el elemento de medida está disponible. Me he tropezado con esto también.
n0rm
-3

para mí, configurar las Dimensiones para usar% es lo que funcionó para mí width:'100%'

pinchez254
fuente
-4

Aquí está el código para obtener las Dimensiones de la vista completa del dispositivo.

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

Úselo así:

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

ravi
fuente
Esto está bien, pero no responde la pregunta.
Moso Akinyemi