Abrufen der Größe einer Ansicht in React Native


147

Ist es möglich, die Größe (Breite und Höhe) einer bestimmten Ansicht zu ermitteln? Zum Beispiel habe ich eine Ansicht, die den Fortschritt zeigt:

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

Ich muss die tatsächliche Breite der Ansicht kennen, um andere Ansichten richtig ausrichten zu können. Ist das möglich?

Antworten:


315

Ab React Native 0.4.2 verfügen View-Komponenten über eine onLayoutRequisite . Übergeben Sie eine Funktion, die ein Ereignisobjekt übernimmt. Das Ereignis nativeEvententhält das Layout der Ansicht.

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

Der onLayoutHandler wird auch aufgerufen, wenn die Größe der Ansicht geändert wird.

Die wichtigste Einschränkung besteht darin, dass der onLayoutHandler erst einen Frame nach dem Mounten Ihrer Komponente aufgerufen wird. Daher möchten Sie möglicherweise Ihre Benutzeroberfläche ausblenden, bis Sie Ihr Layout berechnet haben.


2
Das Problem bei diesem Ansatz ist, dass beim Drehen des Geräts / Ändern der Ansichtsgröße onLayout nicht erneut aufgerufen wird.
Matthew

4
onLayout wird aufgerufen, wenn sich der Rahmen der Ansicht ändert. Möglicherweise ändert Ihre Ansicht ihre Größe oder Position beim Drehen nicht. Sehen Sie sich das onLayout-Beispiel im UIExplorer an, in dem onLayout beim Drehen aufgerufen wird.
Ide

2
Angenommen, ich möchte Viewje nach Abmessung eine unterschiedliche Anzeige durchführen . Ich verstehe nicht, wie ich die onLayoutFunktion der Ansicht verwenden kann, um die Anzeige der Ansicht zu ändern. Führt das nicht zu einer Endlosschleife?
Lane Rettig

2
@ LaneRettig Ja, wenn dies wirklich das ist, was Sie tun möchten, sollten Sie Ihren Code so schreiben, dass ein statisches Gleichgewicht erreicht wird. Es hört sich jedoch so an, als ob Sie Ihre Ansicht nur an die Bildschirmabmessungen anpassen möchten. In diesem Fall onLayouthängt dies nicht zusammen.
Ide

7
@ide Wie würden Sie die Benutzeroberfläche ausblenden, bis das Layout berechnet ist?
Irfanlone

27

Dies ist das einzige, was für mich funktioniert hat:

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

14

Wenn Sie die Größe festlegen und ändern möchten, stellen Sie sie im Layout wie folgt ein:

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

Sie können viel mehr Variationen davon erstellen, wie es geändert werden soll, indem Sie dies in einer anderen Komponente verwenden, die eine andere Ansicht als Wrapper hat, und einen onResponderRelease-Rückruf erstellen, der den Ort des Berührungsereignisses in den Status übergibt, der dann an die untergeordnete Komponente übergeben werden kann als Eigenschaft, die den aktualisierten Status von onLayout durch Platzieren {[styles.View2, this.state.view2LayoutProps, this.props.touchEventTopLeft]}usw. überschreiben könnte .


11

Sie können das DimensionsModul direkt verwenden und Ihre Ansichtsgrößen berechnen. DimensionsGeben Sie Ihnen tatsächlich die Hauptfenstergrößen an.

import { Dimensions } from 'Dimensions';

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

Ich hoffe, Ihnen zu helfen!

Update : Wenn Sie heute native StyleSheetmit Flex- Arrangements für Ihre Ansichten verwenden, können Sie in weiten Fällen sauberen Code mit eleganten Layoutlösungen schreiben, anstatt Ihre Ansichtsgrößen zu berechnen ...

Obwohl das Erstellen von benutzerdefinierten Rasterkomponenten , die auf Ereignisse zur Größenänderung des Hauptfensters reagieren, eine gute Lösung für einfache Widget-Komponenten darstellen könnte


3
Gah, warum ist das nicht klarer dokumentiert!?! Ich habe versucht 'Breite' und 'Höhe' anstelle von ('Fenster'). Breite usw.

272
Das von Ihnen angegebene Beispiel enthält die Abmessungen des Fensters und nicht einer bestimmten Ansicht. Wie ist das relevant?
Mark Amery

1
@ MarkAmery mit Fensterabmessungen können Sie planen, wie Ihre Ansichten aussehen werden
Bruno Guerra

2
@BrunoGuerra Können Sie den Code anzeigen, um eine bestimmte Ansichtsgröße (nicht Fenstergröße) nach Dimensionen zu erhalten?
Spark.Bao

4
Die Abmessungen werden auf vielen Geräten nicht aktualisiert, wenn das Gerät gedreht wird. Dies ist ein bekanntes Problem und scheint ab dem reaktionsnativen 0.32.0-rc.0
Glenn Lawrence

10

Vielleicht können Sie verwenden 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);
}

Für mein Leben kann ich nicht herausfinden, wie man es richtig benutzt NativeMethodsMixin. Egal was ich mache, measureist immer undefiniert. Irgendwelche Hinweise?
Chandlervdw

2
Sie müssen NativeMethodsMixindie Funktion nicht verwenden, sie ist nur für einige Elemente verfügbar. Zum Beispiel TouchableWithFeedbackhat die Messfunktion, ein Regular Touchablejedoch nicht. Versuchen Sie, den von ViewIhnen verwendeten Typ zu ändern , holen Sie sich die Referenz und prüfen Sie, ob das Kennzahlelement verfügbar ist. Ich bin auch darüber gestolpert.
n0rm

-3

Für mich hat es funktioniert, die Dimensionen auf% zu setzen width:'100%'


-4

Hier ist der Code, um die Abmessungen der vollständigen Ansicht des Geräts abzurufen.

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

Verwenden Sie es so:

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


Das ist okay, aber es beantwortet die Frage nicht.
Moso Akinyemi
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.