【React Native】measureInWindow在安卓上无法正确获取View在屏幕上的布局信息

问题描述:

在React Native中,我们可以使用measureInWindow的方式去获取一个View在屏幕中的位置信息:

下面这个Demo中,我们写了一个页面HomePage和一个列表项组件ListItemA,我们期望每过5s监测一次列表中每一项在屏幕中的位置信息。

于是,我们使用useRef得到了一个ref对象,并且将ref指向ListItemA最外层的View。之后,我们每5s调用ref.current的measureInWindow方法以获取列表项在屏幕中的位置信息。

HomePage.tsx:

typescript 复制代码
import React, { type FC, memo } from 'react';
import { StyleSheet, View } from 'react-native';
import { FlatList } from 'react-native-gesture-handler';

import ListItemA from './ListItem';

const styles = StyleSheet.create({
  container: {
    height: '100%',
    backgroundColor: 'red',
    alignItems: 'center',
    justifyContent: 'center',
  },
  text: {
    fontSize: 32,
    color: '#f55',
  },
});
const HomePage: FC<{}> = () => {
  const data = ['商品1', '商品2', '商品3', '商品4', '商品5'];
  return (
    <View style={styles.container}>
      <FlatList
        style={{
          width: '100%',
          paddingHorizontal: 12,
        }}
        data={data}
        renderItem={({ item, index }) => {
          return <ListItemA index={index} title={item} />;
        }}
      />
    </View>
  );
};
export default memo(HomePage);

ListItemA.tsx:

typescript 复制代码
import React, { useEffect, useRef } from 'react';
import { StyleSheet, Text, View } from 'react-native';

interface IProps {
  index: number;
  title: string;
}
const styles = StyleSheet.create({
  container: {
    width: '100%',
    height: 40,
    borderRadius: 12,
    backgroundColor: '#ff00ff',
    marginTop: 12,
    flexDirection: 'column',
    justifyContent: 'center',
  },
  text: {
    fontSize: 14,
    color: '#000000',
  },
});
const ListItemA = (props: IProps) => {
  const ref = useRef<View>(null);
  useEffect(() => {
  	// 每5s获取一次
    const timer = setInterval(() => {
      ref.current?.measureInWindow((x: number, y: number, width: number, height: number) => {
        console.log(props.index, '=>', x, y, width, height);
      });
    }, 5000);
    return () => {
      clearInterval(timer);
    };
  }, []);
  return (
    <View
      ref={ref}
      style={{
        width: '100%',
        flexDirection: 'row',
      }}
    >
      <View style={styles.container}>
        <Text style={styles.text}>{`item${props.index}: ${props.title}`}</Text>
      </View>
    </View>
  );
};
export default ListItemA;

在Android手机上运行后,发现控制台log信息如下:

获取到的布局信息(屏幕中x坐标、屏幕中y坐标、View的宽度,View的高度)均为0。在我打开android的通知栏,再收起,打印信息甚至又发生了改变(这个数据如何得出暂时未知):

可以发现问题:

  1. 最开始无法获取到View的布局信息
  2. 会获取到未知错误信息(原因不详)
  3. 所有的列表项获取到的布局信息是一致的,每个列表项在屏幕中的坐标必然不同,此现象显然不符合预期

问题解决:

React Native针对android会有渲染优化,默认开启。
collapsable属性

我们ListItemA中的最外层View只是用来包裹了内层的View,没有其他的作用。即使在代码中移除了它,展示样式看起来也不会有变化。如果想要使用最外层View获取到布局信息,可以禁用优化,添加collapsable={false}以解决:

修改部分如下:

typescript 复制代码
	<View
      ref={ref}
      collapsable={false}
      style={{
        width: '100%',
        flexDirection: 'row',
      }}
    >
      <View style={styles.container}>
        <Text style={styles.text}>{`item${props.index}: ${props.title}`}</Text>
      </View>
    </View>

这时候再看打印,能够正确获取到每个列表item的布局信息了:

相关推荐
alexhilton1 天前
面向开发者的系统设计:像建筑师一样思考
android·kotlin·android jetpack
CYRUS_STUDIO1 天前
用 Frida 控制 Android 线程:kill 命令、挂起与恢复全解析
android·linux·逆向
CYRUS_STUDIO1 天前
Frida 实战:Android JNI 数组 (jobjectArray) 操作全流程解析
android·逆向
小仙女喂得猪1 天前
2025 Android原生开发者角度的React/ReactNative 笔记整理
react native·react.js
用户092 天前
Gradle Cache Entries 深度探索
android·java·kotlin
循环不息优化不止2 天前
安卓 View 绘制机制深度解析
android
叽哥2 天前
Kotlin学习第 9 课:Kotlin 实战应用:从案例到项目
android·java·kotlin
XTransfer技术2 天前
RN也有微前端框架了? Xtransfer的RN优化实践(一)多bundle架构
前端·react native
雨白2 天前
Java 线程通信基础:interrupt、wait 和 notifyAll 详解
android·java
诺诺Okami2 天前
Android Framework-Launcher-UI和组件
android