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

相关推荐
编程洪同学24 分钟前
Spring Boot 中实现自定义注解记录接口日志功能
android·java·spring boot·后端
氤氲息3 小时前
Android 底部tab,使用recycleview实现
android
Clockwiseee3 小时前
PHP之伪协议
android·开发语言·php
小林爱3 小时前
【Compose multiplatform教程08】【组件】Text组件
android·java·前端·ui·前端框架·kotlin·android studio
小何开发4 小时前
Android Studio 安装教程
android·ide·android studio
开发者阿伟5 小时前
Android Jetpack LiveData源码解析
android·android jetpack
weixin_438150995 小时前
广州大彩串口屏安卓/linux触摸屏四路CVBS输入实现同时显示!
android·单片机
CheungChunChiu5 小时前
Android10 rk3399 以太网接入流程分析
android·framework·以太网·eth·net·netd
木头没有瓜6 小时前
ruoyi 请求参数类型不匹配,参数[giftId]要求类型为:‘java.lang.Long‘,但输入值为:‘orderGiftUnionList
android·java·okhttp
键盘侠0076 小时前
springboot 上传图片 转存成webp
android·spring boot·okhttp