问题描述:
在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的通知栏,再收起,打印信息甚至又发生了改变(这个数据如何得出暂时未知):
可以发现问题:
- 最开始无法获取到View的布局信息
- 会获取到未知错误信息(原因不详)
- 所有的列表项获取到的布局信息是一致的,每个列表项在屏幕中的坐标必然不同,此现象显然不符合预期
问题解决:
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的布局信息了: