React-Native : measure a View
Asked Answered
E

3

19

I'm trying to measure a view using a ref, but the width returned is 0 despite the fact that I see the view displayed on the screen (and it's far from being equal to 0).

I tried to follow this : https://github.com/facebook/react-native/issues/953 but it just doesn't work ... I just want to get the actual width of the View.

Here is my code :

var Time = React.createClass({
  getInitialState: function() {
    return({ progressMaxSize: 0 }); 
  },
  componentDidMount: function() {
    this.measureProgressBar();
  },
  measureProgressBar: function() {
    this.refs.progressBar.measure(this.setWidthProgressMaxSize);
  },
  setWidthProgressMaxSize: function(ox, oy, width, height, px, py) {
    this.setState({ progressMaxSize: width });
  },
  render: function() {
    return(
      <View style={listViewStyle.time} ref="progressBar">
        <View style={listViewStyle.progressBar} >
          <View style={[listViewStyle.progressMax, { width: this.state.progressMaxSize }]}/>
        </View>
      </View>
    );
  }
}); 

The styles associated :

time: {
    position: 'absolute',
    bottom: 5,
    left: 5,
    right: 5,
    backgroundColor: '#325436',
    flexDirection: 'row',
  },
  progressBar: {
    flex: 1,
    backgroundColor: '#0000AA',
  },
  progressMax: {
    position: 'absolute',
    top: 0,
    left: 0,
    backgroundColor: '#000',
    height: 30, 
  },
Electrophysiology answered 23/4, 2015 at 16:11 Comment(0)
E
8

During the night some guys talked about a (hacky) solution but it solved my problem, found it here: https://github.com/facebook/react-native/issues/953

Basically the solution is to use setTimeout and everything just works magically:

componentDidMount: function() {
  setTimeout(this.measureProgressBar);
},

measureProgressBar: function() {
  this.refs.progressBar.measure((a, b, width, height, px, py) =>
    this.setState({ progressMaxSize: width })
  );
}
Electrophysiology answered 24/4, 2015 at 8:41 Comment(4)
You can also use requestAnimationFrame.Culicid
I get undefined is not an object (evaluating 'this.refs'). What's going on?Courageous
you need to bind measureProgressBar, this.measureProgressBar.bind(this)Ki
It might be more efficient to only call measure in a callback passed to onLayout on your view.Extempore
B
19

To measure view size, no need to use ref at all. You can get it from nativeEvent passed by onLayout.

measureView(event: Object) {
   console.log(`*** event: ${JSON.stringify(event.nativeEvent)}`);
   // you'll get something like this here:
   // {"target":1105,"layout":{"y":0,"width":256,"x":32,"height":54.5}}
}

render() {
    return (
        <View onLayout={(event) => {this.measureView(event)}} />
    );
}
Barcroft answered 4/6, 2018 at 15:50 Comment(2)
onLayout doesn't call in some cases specially on Android.Illustrative
That's correct @UmarFarooqAwan, but if you set collapsable={false} it will always measure. In Android some Views are removed if they have no visible impact.Vesicatory
F
9

You want to measure the progress bar onLayout.

var Time = React.createClass({
  getInitialState: function() {
    return({ progressMaxSize: 0 }); 
  },
  measureProgressBar: function() {
    this.progressBar.measure(this.setWidthProgressMaxSize);
  },
  setWidthProgressMaxSize: function(ox, oy, width, height, px, py) {
    this.setState({ progressMaxSize: width });
  },
  render: function() {
    return(
      <View style={listViewStyle.time} ref={(c) => { this.progressBar = c; } onLayout={this.measureProgressBar}>
        <View style={listViewStyle.progressBar} >
          <View style={[listViewStyle.progressMax, { width: this.state.progressMaxSize }]}/>
        </View>
      </View>
    );
  }
});
Finlay answered 23/8, 2017 at 14:53 Comment(3)
This is currently the best solution. I'm using React Native 0.50.4 and using a string ref is deprecated. Furthermore, the measure function of View will not return valid data unless onLayout is triggered at least once.Alloplasm
Actually somebody could tell me what ox, oy, width, height, px and py specifically mean?Mould
ox: offset x -> is space from x axis.Settlement
E
8

During the night some guys talked about a (hacky) solution but it solved my problem, found it here: https://github.com/facebook/react-native/issues/953

Basically the solution is to use setTimeout and everything just works magically:

componentDidMount: function() {
  setTimeout(this.measureProgressBar);
},

measureProgressBar: function() {
  this.refs.progressBar.measure((a, b, width, height, px, py) =>
    this.setState({ progressMaxSize: width })
  );
}
Electrophysiology answered 24/4, 2015 at 8:41 Comment(4)
You can also use requestAnimationFrame.Culicid
I get undefined is not an object (evaluating 'this.refs'). What's going on?Courageous
you need to bind measureProgressBar, this.measureProgressBar.bind(this)Ki
It might be more efficient to only call measure in a callback passed to onLayout on your view.Extempore

© 2022 - 2024 — McMap. All rights reserved.