facebook / react-native

A framework for building native applications using React

Home Page:https://reactnative.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[Android] measure not returning values unless element has onLayout property

oblador opened this issue · comments

I have something similar to this:

handleSomething: function() {
  this._root.measure((ox, oy, width, height, px, py) => {
    console.log({ox, oy, width, height, px, py});
  });
},
render: function() {
  return (<View ref={component => this._root = component}>...</View>);
}

This code works flawlessly on iOS, but on android the measure callback will always be called with undefined arguments – unless I put an empty callback on the onLayout property.

@oblador what happens if, instead of logging arguments, you log ox, oy etc.?

@foghina: they log as undefined, logging arguments is just shorter to write.

@oblador I know about arguments, we just ran into this internally and it turned out arguments was wrong for some reason, but logging the arguments by name worked.

Can you try wrapping the measure call in requestAnimationFrame? E.g.:

this.requestAnimationFrame(() => {
  this._root.measure((ox, oy, width, height, px, py) => {
    console.log(arguments);
  });
});

@foghina "arguments" in an arrow function refers to the enclosing non-arrow function's arguments (same scoping as "this"). Maybe that was the issue you were seeing.

@ide that does not explain why it works on iOS :-/

There was a timing change with how iOS does measurement that may have fixed this issue. Haven't really looked into it in detail, but it might be related? aa62a5e

I've updated the issue to not confuse anybody. It works as expected on iOS for all I know, but not on android. Wasn't aware of arrow functions inheriting the arguments object, but it's unrelated to this issue.

@oblador does wrapping the call in a rAF callback help?

@ide haven't tried, but don't really understand why it would make a difference. handleSomething is supposed to be a Touchable* callback.

Yeah you're probably right.

I'm also experiencing this. Along with onLayout, I've found that setting renderToHardwareTextureAndroid={true} on the view also makes measure return values.

@oblador @marcshilling can you try collapsable: false prop on your view? Android may remove the view from hierarchy for optimization purpose.

I just ran into something similar.

https://facebook.github.io/react-native/docs/view.html#content

I have same problem and can confirm that using onLayout or collapsable={false} helps

commented

@chirag04 collapsable: false helped for me, thanks.

@chirag04 tells me to close this issue. If you think it should still be opened let us know why.

FYI, I'm using 0.26.3 and this was still an issue. I had to add an empty onLayout before measure would return integers instead of just undefined.

I am having trouble with this on iOS as well.

Was this fixed in a more recent version? Using the unrelated properties onLayout or collapsable to force this functionality seems to me to be a hack rather than a fix. I know there are limited resources to fix things, but at least there could be something in the docs about it?

@chirag04 you closed this but it's actually not resolved.

  1. There are no docs
  2. There is no actual fix.

Also the y position (second argument) is always 0 if the element you are measuring is in a scroll view (with collapsable) . Joy.

I can confirm the bug is still here

commented

Also still seeing this issue, will report back with any findings.

this bug still exists

@zoharlevin @MattFoley @julien-rodrigues Do you guys see this even after setting collapsable:false on your view?

confirm that [v0.35.0]

commented

Can be closed. collapsable: false fixes that one, just ran into it.

I still see the issue of y coming through as 0 for Android, even after setting collapsable={false} on the View. Again, working fine in iOS.

@JAStanton I also tried setting collapsable={false} on the ScrollView up the tree, but that still did not help.

@grabbou I have a situation that is not resolved with collapsable.

i am using react native version 0.36 and got this issues on Android, but on iOS it work well
here is my code ,

this.refs.field.measure((x, y, width, height, px, py) => { console.log('---------- height ',height) )}

height is undefined
??
pls help me, many thanks

setting collapsable={false} on a View solved this problem for me. I'm on 0.39.2

@chirag04 collapsable={false} Thanks, it works!

I was still experiencing the issue with collapsable={false}.

What fixed it for me was adding onLayout={() => {}} instead.

Using measureLayout (relative to specific node) seemed to solve this for me.

I was experiencing this issue on Views and managed to work around it by adding empty onLayout as suggested.

However now I am trying to measure a ScrollView and adding onLayout did not fix the issue. I managed to work around it by wrapping all the content of my ScrollView with a View, adding an empty onLayout to that View, and then measuring that View.

commented

I have the same problem, but props arent undefined.

I have a listview with this rows:

  renderRow(rowData, sectionID, rowID) {
    return (
      <View
        style={{padding: 20, backgroundColor: rowData.color, marginHorizontal: 20, marginVertical: 10, alignItems: 'center'}}
        ref={(row) => this.rows[rowID] = row}
        collapsable={false}
        {...this.customPanResponder.panHandlers}
      >
        <Text>{rowData.text}</Text>
      </View>
    )
  }

With

    _.map(this.rows, row => {
          row.measure( (ox, oy, width, height, px, py) => console.log("ox: ", ox, " oy: ", oy, " height: ", height, " px: ", px, " py: ", py))
        })

On iOS measure logs:

ox:  20  oy:  10  height:  57  px:  20  py:  74
ox:  20  oy:  87  height:  57  px:  20  py:  151
ox:  20  oy:  164  height:  57  px:  20  py:  228

On Android measure logs:

ox:  0  oy:  0  height:  59  px:  20  py:  66
ox:  0  oy:  0  height:  59  px:  20  py:  145
ox:  0  oy:  0  height:  59  px:  20  py:  224

Why my oy on android is always 0?

I just found that on iOS, measuring a Text component nested in another Text component results in all 0's as well. Haven't tested on Android yet. Also noted that onLayout on a nested Text component is never called, very strange.

@SteffeyDev I think it have something to do with the way they render nested Text Component. Basically they used attributed text on the outermost Text element and all the nested ones are parsed to be merged into the parent as 1 large text item. That's how I think it's on iOS.

@joturako That makes sense, and explains why I can't get layout information. If I have a large body of text in a scrollview, how would you recommend I find the position of a smaller portion so that I can scroll there? Or is there no way to do that?

@SteffeyDev I think you have to write a custom component, for iOS for example you can look for more information on how to scroll a UITextView to a selection: [textView scrollRangeToVisible:[textView.text rangeOfString:@"Lorem ipsum"]];

Hi there! This issue is being closed because it has been inactive for a while. Maybe the issue has been fixed in a recent release, or perhaps it is not affecting a lot of people. Either way, we're automatically closing issues after a period of inactivity. Please do not take it personally!

If you think this issue should definitely remain open, please let us know. The following information is helpful when it comes to determining if the issue should be re-opened:

  • Does the issue still reproduce on the latest release candidate? Post a comment with the version you tested.
  • If so, is there any information missing from the bug report? Post a comment with all the information required by the issue template.
  • Is there a pull request that addresses this issue? Post a comment with the PR number so we can follow up.

If you would like to work on a patch to fix the issue, contributions are very welcome! Read through the contribution guide, and feel free to hop into #react-native if you need help planning your contribution.

I know this is closed but for anyone else who hit this when trying to get the x and y coordinates within a ScrollView, using measureLayout as @wschurman (thanks!) suggested worked for me.

For example:

import { findNodeHandle, ScrollView, View } from 'react-native'

...

this.VIEW_REF.measureLayout(
  findNodeHandle(this.SCROLLVIEW_REF),
  function(x, y) {
    console.log(x, y);
  }, 
  function(error) {
    console.log(error);
  }
);

...

render() {
  return (
    <ScrollView ref={ref => SCROLLVIEW_REF = ref}>
      <View ref={ref => VIEW_REF = ref}>
        ...
      </View>
    </ScrollView>
  );
}

Still hitting this issue when using measureInWindow() with React Native 0.54.2.