Obter tamanho de uma visualização no React Native

147

É possível obter o tamanho (largura e altura) de uma determinada visualização? Por exemplo, eu tenho uma visão mostrando o progresso:

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

Preciso saber a largura real da visualização para alinhar outras visualizações corretamente. Isso é possível?

Mateus
fonte

Respostas:

315

No React Native 0.4.2, os componentes View têm um onLayoutsuporte . Passe uma função que aceita um objeto de evento. O evento nativeEventcontém o layout da exibição.

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

O onLayoutmanipulador também será chamado sempre que a exibição for redimensionada.

A principal ressalva é que o onLayoutmanipulador é chamado pela primeira vez um quadro após a montagem do seu componente, portanto, você pode ocultar sua interface do usuário até calcular o layout.

ide
fonte
2
A questão dessa abordagem é que, quando o dispositivo gira / exibe alterações de tamanho, não recebo o onLayout chamado novamente.
Matthew
4
onLayout é chamado quando o quadro da exibição é alterado. Talvez sua visão não mude seu tamanho ou posição na rotação. Veja o exemplo onLayout no UIExplorer, onde onLayout é chamado na rotação.
Id
2
Digamos que eu queira exibir um modo Viewdiferente, dependendo das dimensões. Não entendo como posso usar a onLayoutfunção do modo de exibição para alterar como exibo o modo de exibição. Isso não leva a um loop infinito?
Lane Rettig
2
@LaneRettig Sim, o faz se realmente é o que você deseja fazer, então você deve escrever seu código de maneira a alcançar o equilíbrio estático. Mas parece que você pode querer personalizar sua exibição com base nas dimensões da tela, caso em que onLayoutnão está relacionado.
ide
7
@ide como você ocultaria a interface do usuário até que o layout seja computado?
Irfanlone 29/08
27

Esta é a única coisa que funcionou para mim:

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

Basicamente, se você deseja definir o tamanho e fazer alterações, defina-o como no layout da seguinte maneira:

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

Você pode criar muito mais variações de como ela deve ser modificada, usando-a em outro componente que possui Outra visualização como wrapper e crie um retorno de chamada onResponderRelease, que pode passar o local do evento de toque para o estado, que pode ser passado ao componente filho como propriedade, que pode substituir o estado atualizado onLayout, colocando {[styles.View2, this.state.view2LayoutProps, this.props.touchEventTopLeft]}e assim por diante.

juslintek
fonte
11

Você pode usar diretamente o Dimensionsmódulo e calcular os tamanhos das visualizações. Na verdade, Dimensionsforneça os tamanhos da janela principal.

import { Dimensions } from 'Dimensions';

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

Espero ajudá-lo!

Atualização : Hoje, usando o nativo StyleSheetcom o Flex organizando suas visualizações ajuda a escrever código limpo com soluções elegantes de layout em casos amplos, em vez de calcular o tamanho das visualizações ...

Embora a construção de componentes de grade personalizados , que respondem a eventos de redimensionamento da janela principal, possam produzir uma boa solução em componentes simples do widget

Bruno Guerra
fonte
3
Gah, por que isso não está documentado com mais clareza!?! Eu estava tentando 'largura' e 'altura' em vez de ('janela'). Largura etc.
272
O exemplo que você fornece fornece as dimensões da janela , não de uma determinada exibição; como isso é relevante?
Mark Amery
1
@MarkAmery com as dimensões das janelas, você pode planejar como serão as suas visualizações #
Bruno Guerra
2
@BrunoGuerra, você pode mostrar o código para obter um determinado tamanho de exibição (não janela) por Dimensões?
Spark.Bao
4
O Dimensions não é atualizado em muitos dispositivos quando o dispositivo é girado. Este é um conhecido problema e não parece ser fixado a partir de reagir nativo 0.32.0-rc.0
Glenn Lawrence
10

Talvez você possa 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
fonte
Pela minha vida, não consigo descobrir como usá-lo corretamente NativeMethodsMixin. Não importa o que eu faça, measureé sempre indefinido. Alguma dica?
chandlervdw
2
Você não precisa usar NativeMethodsMixina função está disponível apenas em alguns elementos. Por exemplo TouchableWithFeedback, tem a função de medida, mas um regular Touchablenão. Tente alterar o tipo que Viewvocê está usando, obtenha a ref e verifique se o elemento de medida está disponível. Eu tropecei nisso também.
N0rm 17/01/19
-3

para mim, definir as dimensões para usar% é o que funcionou para mim width:'100%'

pinchez254
fonte
-4

Aqui está o código para obter as dimensões da visualização completa do dispositivo.

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

Use-o assim:

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

Ravi
fonte
Está tudo bem, mas não responde à pergunta.
Moso Akinyemi