Uzyskaj rozmiar widoku w React Native

147

Czy można uzyskać rozmiar (szerokość i wysokość) określonego widoku? Na przykład mam widok pokazujący postęp:

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

Muszę znać rzeczywistą szerokość widoku, aby prawidłowo wyrównać inne widoki. czy to możliwe?

Mateusz
źródło

Odpowiedzi:

315

Począwszy od React Native 0.4.2, zobacz komponenty mają onLayoutrekwizyt . Przekaż funkcję, która przyjmuje obiekt zdarzenia. Wydarzenie nativeEventzawiera układ widoku.

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

Procedura onLayoutobsługi będzie również wywoływana za każdym razem, gdy rozmiar widoku zostanie zmieniony.

Głównym zastrzeżeniem jest to, że program onLayoutobsługi jest najpierw wywoływany jedną klatkę po zamontowaniu komponentu, więc możesz chcieć ukryć interfejs użytkownika, dopóki nie obliczysz układu.

ide
źródło
2
Problem z tym podejściem polega na tym, że gdy urządzenie obraca się / zmienia rozmiar widoku, nie pojawia się ponowne wywołanie onLayout.
Matthew
4
onLayout jest wywoływany, gdy zmienia się ramka widoku. Być może twój widok nie zmienia swojego rozmiaru ani pozycji podczas obrotu. Spójrz na przykład onLayout w UIExplorer, gdzie onLayout jest wywoływany podczas obracania.
ide
2
Powiedzmy, że chcę wyświetlić Viewinaczej w zależności od wymiarów. Nie rozumiem, jak mogę użyć funkcji widoku, onLayoutaby zmienić sposób wyświetlania widoku. Czy to nie prowadzi do nieskończonej pętli?
Lane Rettig
2
@LaneRettig Tak, to robi, więc jeśli naprawdę chcesz to zrobić, powinieneś napisać kod w taki sposób, aby osiągnąć równowagę statyczną. Ale wygląda na to, że możesz chcieć po prostu dostosować widok na podstawie wymiarów ekranu, w którym onLayoutto przypadku nie ma to związku.
ide
7
@ide, jak możesz ukryć interfejs użytkownika do czasu obliczenia układu?
Irfanlone
27

To jedyna rzecz, która zadziałała dla mnie:

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
źródło
14

Zasadniczo, jeśli chcesz ustawić rozmiar i zmienić go, ustaw go na stan w układzie w następujący sposób:

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

Możesz stworzyć o wiele więcej wariantów tego, jak powinno być zmodyfikowane, używając tego w innym komponencie, który ma inny widok jako opakowanie i utworzyć wywołanie zwrotne onResponderRelease, które może przekazać lokalizację zdarzenia dotyku do stanu, który może być następnie przekazany do komponentu podrzędnego jako właściwość, która może przesłonić zaktualizowany stan onLayout przez umieszczenie {[styles.View2, this.state.view2LayoutProps, this.props.touchEventTopLeft]}i tak dalej.

juslintek
źródło
11

Możesz bezpośrednio skorzystać z Dimensionsmodułu i obliczyć rozmiary swoich widoków. Właściwie to Dimensionspodaj główne rozmiary okien.

import { Dimensions } from 'Dimensions';

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

Mam nadzieję, że ci pomogę!

Aktualizacja : Dzisiaj korzystam StyleSheetz natywnych z Flex rozmieszczeniem w widokach pomaga pisać czysty kod z eleganckimi rozwiązaniami układu w szerokich przypadkach zamiast obliczać rozmiary widoków ...

Chociaż tworzenie niestandardowych komponentów siatki , które reagują na zdarzenia zmiany rozmiaru okna głównego, może dać dobre rozwiązanie w przypadku prostych komponentów widgetów

Bruno Guerra
źródło
3
Gah, dlaczego nie jest to lepiej udokumentowane!?! Próbowałem „szerokość” i „wysokość” zamiast („okno”). Szerokość itp.
272
Podany przez ciebie przykład podaje wymiary okna , a nie danego widoku; jakie to ma znaczenie?
Mark Amery
1
@MarkAmery dzięki wymiarom okien możesz zaplanować, jak będą wyglądać Twoje widoki
Bruno Guerra
2
@BrunoGuerra Czy możesz pokazać kod, aby uzyskać określony rozmiar widoku (nie okna) według wymiarów?
Spark.Bao
4
Wymiary nie są aktualizowane na wielu urządzeniach, gdy urządzenie jest obrócone. Jest to znany problem i nie wydaje się, aby został naprawiony w wersji 0.32.0-rc.0
Glenn Lawrence
10

Może możesz użyć 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
źródło
Przez całe życie nie potrafię wymyślić, jak właściwie używać NativeMethodsMixin. Nieważne, co robię, measurezawsze jest nieokreślone. Jakieś wskazówki?
chandlervdw
2
Nie musisz korzystać NativeMethodsMixinz funkcji, która jest dostępna tylko dla niektórych elementów. Na przykład TouchableWithFeedbackma funkcję pomiaru, ale zwykła Touchablenie. Spróbuj zmienić typ, Viewktórego używasz, pobierz referencję i sprawdź, czy element miary jest dostępny. Ja też się na to natknąłem.
n0rm
-3

dla mnie ustawienie wymiarów na użycie% działa dla mnie width:'100%'

pinchez254
źródło
-4

Oto kod, aby uzyskać wymiary pełnego widoku urządzenia.

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

Użyj tego w ten sposób:

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

ravi
źródło
To jest w porządku, ale nie odpowiada na pytanie.
Moso Akinyemi