6

I am working on a react native app and I want to handle touches on screen.

One use case is when the user "press" on screen, I want to be able to get the position (x,y) of a specific component on screen to know if it matches the (x,y) of the touch.

I've searched already on stack overflow, but none of the given solutions worked...

In my root component:

_onPress = () => {
    // How can I get the position of my component ?
    this._myComponent.xxx();
};

render() {
    return (
        <View><MyComponent ref={(r) => this._myComponent = r;} /></View>
    );
}

EDIT: After trying this solution (React Native: Getting the position of an element) I made it work as follow:

In MyComponent.js:

getPosition () => {
    this._ref._component.measure((width, height, px, py, fx, fy) => {
        const location = {
            fx: fx,
            fy: fy,
            px: px,
            py: py,
            width: width,
            height: height
        }
        console.log(location)
    });
};

render() {
    return (
        <View ref={(r) => { this._ref = r;} } />
    );
}

Thanks for your help!

Alexis Santini
  • 331
  • 1
  • 3
  • 17

3 Answers3

5

React Native

You can use .measure():

this._myComponent._component.measure((width, height, px, py, fx, fy) => {
  // do positioning checks here
}

Determines the location on screen, width, and height of the given view and returns the values via an async callback. If successful, the callback will be called with the following arguments: x, y, width, height, pageX, pageY.

Docs: https://facebook.github.io/react-native/docs/direct-manipulation.html#other-native-methods


Web API (no React Native)

If you're working with a DOM node, you can use Element.getBoundingClientRect():

let domRect = this._myComponent.getBoundingClientRect();
let { x, y } = domRect;

The result is the smallest rectangle which contains the entire element, with read-only left, top, right, bottom, x, y, width, and height properties describing the overall border-box in pixels. Properties other than width and height are relative to the top-left of the viewport.

Docs: https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect

Simone
  • 20,302
  • 14
  • 79
  • 103
  • 1
    The question is about React Native, not React DOM. Will this solution work in React Native? – rishat Nov 24 '17 at 10:40
  • Sorry, didn't see the tag. I'm not sure about React Native. This is what I found on the docs, it might help: https://facebook.github.io/react-native/docs/dimensions.html – Simone Nov 24 '17 at 10:42
  • It doesn't work in my case because I am using react native, so this is no dom elements. The 'Dimensions' API is useful to get the width and height of the viewport and not its coordinates. – Alexis Santini Nov 24 '17 at 10:44
  • 1
    @AlexisSantini this SO question has what you're looking for: https://stackoverflow.com/questions/30096038/react-native-getting-the-position-of-an-element – Simone Nov 24 '17 at 10:45
  • I've updated my answer with the right solution for React Native – Simone Nov 24 '17 at 10:50
  • Ok so I tried both solutions and the one in your previous comment worked (https://stackoverflow.com/questions/30096038/react-native-getting-the-position-of-an-element). – Alexis Santini Nov 24 '17 at 10:53
  • However, I tried your update and it tells me 'this._myComponent.measure' is not a function – Alexis Santini Nov 24 '17 at 10:54
  • My bad, I think it should be `this._myComponent._component.measure(...)` — can you confirm that it works for you? – Simone Nov 24 '17 at 11:04
  • 2
    Yes it does! After reading between the lines in the react native doc, I came to this conclusion: The difference between calling: this._myComponent.measure() & this._myComponent._component.measure() is in the fact that in this case MyComponent renders an "Animated.View" instead of a View and the measure function can be called on any View, but if you want to call it on something else (eg. Not a "native view") you can by referencing this "_component" property. – Alexis Santini Nov 24 '17 at 11:27
  • Cool, glad to hear it worked :) I'll update my answer again then – Simone Nov 24 '17 at 11:30
5

For an example in a functional component using useRef in React Native:

const BoardSquare = props => {
  const squareRef = useRef(null);

  console.log('squareRef', squareRef);

  const doMeasure = square => {
    squareRef.current.measure((width, height, px, py, fx, fy) => {
      const location = {
        fx: fx,
        fy: fy,
        px: px,
        py: py,
        width: width,
        height: height,
      };
      console.log('location', location);
      square.x = fx;
      square.y = fy;
      square.xMax = fx + px;
      square.yMax = fy + py;
    });
  };

  return (
    <Square
      {...props}
      ref={squareRef}
      filled={props.square.filled}
      onLayout={() => doMeasure(props.square)}
    />
  );
};
Kevin Williams
  • 224
  • 3
  • 5
0

Another option is to use onLayout. Example

const [viewHeight, setViewHeight] = React.useState(0);
return (
  <View
    onLayout={e => {
      e.persist();
      setViewHeight(e && e.nativeEvent ? e.nativeEvent.layout.height : 0);
    }}
  />
);

A more in-depth example

Documentation of LayoutEvent

Fanchen Bao
  • 3,310
  • 1
  • 21
  • 34