React Native:获取元素的位置

Joh*_*ein 55 javascript ios reactjs react-native

我正在Image使用flexbox 设计一个组件,使其位于屏幕的中心,效果非常好.现在我希望第二个Image组件直接显示在第一个组件的顶部.第二张图像使用绝对定位.目前我只是猜测像素,以便适合,但当然这不准确,而且可维护性太大.

我几乎都在寻找与jQuery相当的React Native .offset().有没有这样的事情,如果没有最好的方法来达到这个目的?

toh*_*ter 74

React Native提供了一种.measure(...)方法,该方法接受回调并使用组件的偏移量和宽度/高度调用它:

myComponent.measure( (fx, fy, width, height, px, py) => {

    console.log('Component width is: ' + width)
    console.log('Component height is: ' + height)
    console.log('X offset to frame: ' + fx)
    console.log('Y offset to frame: ' + fy)
    console.log('X offset to page: ' + px)
    console.log('Y offset to page: ' + py)
})
Run Code Online (Sandbox Code Playgroud)

例...

下面计算自定义组件呈现后的布局:

class MyComponent extends React.Component {
    render() {
        return <View ref={view => { this.myComponent = view; }} />
    }
    componentDidMount() {
        // Print component dimensions to console
        this.myComponent.measure( (fx, fy, width, height, px, py) => {
            console.log('Component width is: ' + width)
            console.log('Component height is: ' + height)
            console.log('X offset to frame: ' + fx)
            console.log('Y offset to frame: ' + fy)
            console.log('X offset to page: ' + px)
            console.log('Y offset to page: ' + py)
        })        
    }
}
Run Code Online (Sandbox Code Playgroud)

错误说明

  • 请注意,有时组件在componentDidMount()调用之前不会完成渲染.如果您因此得到零measure(...),那么将其包装在一个setTimeout应该解决问题,即:

    setTimeout( myComponent.measure(...), 0 )
    
    Run Code Online (Sandbox Code Playgroud)

  • 这种调用“ measure”的方法对我不起作用。必须传递元素句柄:`const handle = findNodeHandle(this.refs.dropdown); UIManager.measure(handle,(x,y,...)...)` (3认同)
  • 无法读取未定义的属性“应用”。 (3认同)

Mar*_*ery 34

您可以使用它们在组件可用的最早时刻onLayout获取组件的宽度,高度和相对父级位置:

<View
  onLayout={event => {
    const layout = event.nativeEvent.layout;
    console.log('height:', layout.height);
    console.log('width:', layout.width);
    console.log('x:', layout.x);
    console.log('y:', layout.y);
  }}
>
Run Code Online (Sandbox Code Playgroud)

相比于使用.measure()在接受的答案显示,这具有的优点是,你永远不会有反复折腾你的推迟.measure()与通话setTimeout,以确保测量是可用的,但它不会给你的缺点相对偏移到整个页面,只有相对于元素父级的页面.

  • 你可以结合答案 - 在onLayout调用测量() (10认同)
  • x, y 总是 0 与 onlayout 吗? (2认同)

Mr *_*ker 19

我需要在ListView中找到元素的位置,并使用这个类似的代码片段.offset:

const UIManager = require('NativeModules').UIManager;
const handle = React.findNodeHandle(this.refs.myElement);
UIManager.measureLayoutRelativeToParent(
  handle, 
  (e) => {console.error(e)}, 
  (x, y, w, h) => {
    console.log('offset', x, y, w, h);
  });
Run Code Online (Sandbox Code Playgroud)

这假设ref='myElement'我的组件上有一个.

  • 请注意 - 就像接受的答案一样 - 您可能需要在`setTimeout`调用中将调用包装到`UIManager.measureLayoutRelativeToParent`,以防止它从组件生命周期之前的某个点执行此代码时出错.已被渲染.另请注意,对于现代的React Native,您需要从'react-native'`执行`import {UIManager,findNodeHandler},而不是此处显示的要求. (3认同)
  • 此方法使用现已弃用的 API。请使用“event.target.measure”,对于 TypeScript 用户,请将您的引用设置为“View”类型以访问“measure”方法。 (2认同)

Flo*_*Flo 17

如果您使用函数组件并且不想使用 aforwardRef来测量组件的绝对LayoutChangeEvent布局,则可以从回调中获取对它的引用onLayout

这样,你就可以获得元素的绝对位置:

<MyFunctionComp
  onLayout={(event) => {
    event.target.measure(
      (x, y, width, height, pageX, pageY) => {
        doSomethingWithAbsolutePosition({
          x: x + pageX, 
          y: y + pageY,
        });
      },
    );
  }}
/>
Run Code Online (Sandbox Code Playgroud)

使用 React Native 0.63.3 进行测试。

  • 刚刚在 Android 和 RN 0.63.3 上尝试过,它给出了错误的值(例如 x 和 y 的值为 0)。 (2认同)

小智 10

我有一个类似的问题,并通过结合上面的答案解决了

class FeedPost extends React.Component {
  constructor(props) {
    ...
    this.handleLayoutChange = this.handleLayoutChange.bind(this);
  }


handleLayoutChange() {
    this.feedPost.measure( (fx, fy, width, height, px, py) => {
      console.log('Component width is: ' + width)
      console.log('Component height is: ' + height)
      console.log('X offset to page: ' + px)
      console.log('Y offset to page: ' + py)
    })
  }

  render {
    return(
      <View onLayout={(event) => {this.handleLayoutChange(event) }} 
      ref={view => { this.feedPost = view; }} >
...
Run Code Online (Sandbox Code Playgroud)

现在,我可以在日志中看到feedPost元素的位置:

08-24 11:15:36.838  3727 27838 I ReactNativeJS: Component width is: 156
08-24 11:15:36.838  3727 27838 I ReactNativeJS: Component height is: 206
08-24 11:15:36.838  3727 27838 I ReactNativeJS: X offset to page: 188
08-24 11:15:36.838  3727 27838 I ReactNativeJS: Y offset to page: 870
Run Code Online (Sandbox Code Playgroud)


Sky*_*ght 6

ref 参数对象上有一个measureInWindow 属性,可以像这样使用:

const [offset, setOffset] = React.useState();

<View ref={(view) =>
    if(!view) return;
    view.measureInWindow((x, y) => {
        setOffset({ x, y });
    })
}>
</View>
Run Code Online (Sandbox Code Playgroud)


Bri*_*n F 5

在最新版本的 React Native 中,使用 refs 进行计算时,这一点似乎发生了变化。

以这种方式声明引用。

  <View
    ref={(image) => {
    this._image = image
  }}>
Run Code Online (Sandbox Code Playgroud)

并以这种方式找到价值。

  _measure = () => {
    this._image._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)
    })
  }
Run Code Online (Sandbox Code Playgroud)

  • @MarkAmery 例如,如果您使用“Animated.View”而不是“View”,则需要它。 (2认同)