繁体   English   中英

React Native:获取元素的位置

[英]React Native: Getting the position of an element

我正在将带有 flexbox 的Image组件样式化,使其位于屏幕中央,效果很好。 现在我希望第二个Image组件直接显示在第一个组件的顶部。 第二张图片使用绝对定位。 目前我只是在猜测像素以使其适合,但这当然不准确,而且维护性工作太多。

我几乎在寻找与 jQuery 的.offset()等效的 React Native 。 有没有这样的事情,如果没有什么是实现这一目标的最佳方法?

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)
})

例子...

以下计算渲染后的自定义组件的布局:

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)
        })        
    }
}

错误说明

  • 请注意,有时组件在调用componentDidMount()之前并未完成渲染。 如果您从measure(...)得到零,那么将它包装在setTimeout应该可以解决问题,即:

     setTimeout( myComponent.measure(...), 0 )

您可以使用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);
  }}
>

使用.measure()接受的答案中所示的.measure()相比,这样做的优点是您永远不必摆弄使用setTimeout推迟.measure()调用以确保测量可用,但缺点是它不会为您提供相对于整个页面的偏移量,仅提供相对于元素父级的偏移量。

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

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; }} >
...

现在我可以在日志中看到我的 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

我需要在 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);
  });

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

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

以这种方式声明引用。

  <View
    ref={(image) => {
    this._image = image
  }}>

并以这种方式找到价值。

  _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)
    })
  }

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

这样,您就可以获取元素的绝对位置:

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

使用 React Native 0.63.3 测试。

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM