在Web上,获得一个元素的位置信息可以使用 getBoundingClientRect 方法获得,但是在RN的View上,就没有这样的方法了,需要使用RN View的专有方法:measure。
measure的使用需要使用ref获取View(或其他原生RN容器,这里只能是原生RN的容器)引用,然后调用上面的measure方法,这个方法接受一个回调函数,参数分别为 x、y、width、height、pageX、pageY参数(参数按照顺序列举)。
但是如果元素实际未渲染(例如Flatlist中不在屏幕中没有渲染的元素),则无法获得它的位置。
import { useRef, FC } from 'react';
import { ScrollView, View, useWindowDimensions } from 'react-native';
export const TextComp: FC = (props) => {
const viewRef = useRef<View>(null);
const { width: windowHeight } = useWindowDimensions();
const handleScroll = () => {
viewRef.current?.measure?.((x, y, width, height, pageX, pageY) => {
if (pageY < windowHeight) {
console.log('View Appears');
// ...
}
});
}
return (
<ScrollView
style={{ paddingVertical: 1000 }}
handleScroll={handlesScroll}
scrollEventThrottle={16}
>
<View ref={useRef}> ... </View>
</ScrollView>
);
}
在安卓中,一个View如果只用来包含子元素,而不存在任何跟空间有关的属性(例如style、className、onLayout等),那么这个View会被安卓RN底层优化,从而导致这个View在Component Tree上并没有挂载。虽然不会影响页面视觉效果,但是会导致measure返回不可控的数值。
为了防止容器被优化,需要用到 collapsable 属性,例如下面的代码:
import { useRef, FC } from 'react';
import { ScrollView, View, useWindowDimensions } from 'react-native';
export const TextComp: FC = (props) => {
const viewRef = useRef<View>(null);
const { width: windowHeight } = useWindowDimensions();
const handleScroll = () => {
viewRef.current?.measure?.((x, y, width, height, pageX, pageY) => {
if (pageY < windowHeight) {
console.log('View Appears');
// ...
}
});
}
return (
<ScrollView
style={{ paddingVertical: 1000 }}
handleScroll={handlesScroll}
scrollEventThrottle={16}
>
<View
ref={useRef}
collapsable={false} // <---
> ... </View>
</ScrollView>
);
}
除了上述方法外,使用Animated.View、为View添加style属性或者onLayout回调都会防止它被安卓RN优化掉。
2 小时前