14

I know there's

Dimensions.get('window');

But what about a arbitrary view that has no dim string? The arbitrary view could have many subviews. The size of the view is decided by style and layout of the subviews, and it's hard to calculate the size from subviews.

benomatis
  • 5,536
  • 7
  • 36
  • 59
Rick
  • 331
  • 1
  • 4
  • 11

1 Answers1

45

You can measure a view using the onLayout function mentioned here and here. To set it up, you need to call an onLayout function, which takes an event and returns an object, which contains the nativeEvent object. This object contains the x & y coordinates, as well as the width and height of the view.

I've set up an example project implementing the code here:

https://rnplay.org/apps/mbPdZw

Below is a simple setup that measures a view:

'use strict';

var React = require('react-native');
var {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  TouchableHighlight
} = React;

var SampleApp = React.createClass({

  getInitialState() {
        return {
            x: '',
            y: '',
            width: '',
            height: '',
            viewHeight: 100
        }
    },

  measureView(event) {
    console.log('event peroperties: ', event);
    this.setState({
            x: event.nativeEvent.layout.x,
            y: event.nativeEvent.layout.y,
            width: event.nativeEvent.layout.width,
            height: event.nativeEvent.layout.height
        })
    },

    changeHeight() {
        this.setState({
        viewHeight: 200
      })
    },

  render: function() {
    return (
      <View >
       <View onLayout={(event) => this.measureView(event)}  style={{height:this.state.viewHeight, marginTop:120, backgroundColor: 'orange'}}>
                <Text >The outer view of this text is being measured!</Text>
            <Text>x: {this.state.x}</Text>
            <Text>y: {this.state.y}</Text>
            <Text>width: {this.state.width}</Text>
            <Text>height: {this.state.height}</Text>
        </View>

        <TouchableHighlight style={{flexDirection:'row', alignItems: 'center', justifyContent: 'center', padding:15, backgroundColor: '#ddd', marginTop:10}} onPress={() => this.changeHeight() }>
              <Text style={{fontSize:18}}>Change height of container</Text>
        </TouchableHighlight>
      </View>
    );
  }
});

var styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 28,
    textAlign: 'center',
    margin: 10,
  }
});

AppRegistry.registerComponent('SampleApp', () => SampleApp);
Community
  • 1
  • 1
Nader Dabit
  • 52,483
  • 13
  • 107
  • 91
  • 1
    Great answer, but I'm sort of worried about performance. Do you have any idea how this might affect an app's smoothness? – stinodes Dec 20 '16 at 09:00
  • 6
    Calling setState (via measureView) will trigger another render and potentially create an infinite loop. This is not recommended in React Native. https://github.com/facebook/react/issues/5591 – Jason Gore Jun 13 '17 at 00:14