【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的布局信息了:

相关推荐
传奇开心果编程1 小时前
【Jetpack Compose娓娓道来】第29课:状态容器与UI事件建模——把“散装状态”变成“可穷举的契约”
android·kotlin·移动开发·android jetpack·ui框架·开发范式·声明式ui
五彩小白3 小时前
喵呜打卡项目总结
android·团队开发
古法安卓4 小时前
Android-GPU压测工具
android·java·android studio
xcLeigh6 小时前
KingbaseES数据库教程:初识数据库,从安装到跑通第一条SQL
android·数据库·sql·安装·数据库教程·kes
TimeFine9 小时前
AI 编码工作流的设计(二)
android·ai编程
2401_881828329 小时前
MySQL操作命令
android·mysql·adb
用户607097591490610 小时前
AOSP 14 OTA 升级指导(三):三条升级链路——Java API、自研 HAL 与 TR069
android
前端小D11 小时前
React Native Android 项目搭建
android·react native·react.js
恋猫de小郭12 小时前
感人,Flutter 居然有了一个超实用提案,期待落地
android·前端·flutter
CS_Zero13 小时前
安卓开发:Linux的android工具命令
android·linux·运维