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

相关推荐
百锦再6 小时前
Android Studio开发中Application和Activity生命周期详解
android·java·ide·app·gradle·android studio·studio
移动开发者1号7 小时前
Android现代进度条替代方案
android·app
万户猴7 小时前
【Android蓝牙开发实战-11】蓝牙BLE多连接机制全解析1
android·蓝牙
RichardLai887 小时前
[Flutter 基础] - Flutter基础组件 - Icon
android·flutter
前行的小黑炭7 小时前
Android LiveData源码分析:为什么他刷新数据比Handler好,能更节省资源,解决内存泄漏的隐患;
android·kotlin·android jetpack
清霜之辰7 小时前
安卓 Compose 相对传统 View 的优势
android·内存·性能·compose
_祝你今天愉快7 小时前
再看!NDK交叉编译动态库并在Android中调用
android
一杯凉白开7 小时前
Android View 事件的分发机制 四句口诀 先问拦截再派送,子不处理父兜底, 一旦消费无后续, 滑动冲突靠逻辑。
android
冬田里的一把火38 小时前
[Android]导航栏中插入电源菜单
android
星途码客8 小时前
SQLyog中DELIMITER执行存储过程时出现的前置缩进问题
android