React Native FlatList列表项zIndex失效问题求助
FlatList里的Item设置zIndex盖不住BlurView?这么解决
方法一:调层级+开容器溢出
FlatList和BlurView是同级组件,默认后渲染的BlurView层级更高,而且FlatList内部容器默认是overflow: hidden,子组件的zIndex再高也出不去。按下面改:
- 给FlatList加
style={{zIndex: 1}},让它整体层级比BlurView高; - BlurView加
style={{zIndex: 0, ...styles.absolute}},降低它的层级; - 给FlatList加
contentContainerStyle={{overflow: 'visible'}},允许子组件超出FlatList的边界; - 选中的Item设置
zIndex: 2,确保它能盖在BlurView上面。
改完的父组件代码:
<FlatList ref={flatlistRef} data={Array(10).fill(1)} removeClippedSubviews={false} CellRendererComponent={({children}) => children} renderItem={({item, index}) => ( <Items index={index} isSelected={openContextMenu === index + ''} // 把选中状态传给Item /> )} showsVerticalScrollIndicator={false} style={{zIndex: 1}} // 提升FlatList层级 contentContainerStyle={{overflow: 'visible'}} // 允许子组件溢出 /> {openContextMenu ? ( <BlurView style={[styles.absolute, {zIndex: 0}]} // 降低BlurView层级 blurType="light" blurAmount={10} reducedTransparencyFallbackColor="white"> </BlurView> ) : null}
Items组件代码:
<View style={{zIndex: isSelected ? 2 : 0}}> {/* 选中时拉高层级 */} <TouchableOpacity activeOpacity={1} onPress={() => setOpenContextMenu(index + '')}> {isUser ? <RightMessage showAvatar isSelected={isSelected} /> : <LeftMessage />} </TouchableOpacity> </View>
方法二:把选中项单独渲染在FlatList外面
如果方法一在某些平台不好使(比如iOS对ScrollView的overflow支持有限),可以把选中的Item单独拿出来,用绝对定位贴在原位置上,这样直接和BlurView同级,层级随便调。
步骤:
- 点击Item时,获取它的屏幕位置;
- 在FlatList外面渲染一个一模一样的Item,绝对定位到对应位置,给个更高的zIndex。
示例父组件代码:
import { findNodeHandle, UIManager } from 'react-native'; // 父组件加这两个状态 const [selectedItemRect, setSelectedItemRect] = useState(null); const [selectedIndex, setSelectedIndex] = useState(null); // 获取选中Item的位置 const getItemPosition = (index) => { const itemHandle = findNodeHandle(document.getElementById(`item-${index}`)); // 给每个Item加个id UIManager.measure(itemHandle, (_, __, width, height, pageX, pageY) => { setSelectedItemRect({ x: pageX, y: pageY, width, height }); }); }; // 点击Item的处理函数 const onItemPress = (index) => { setOpenContextMenu(index + ''); setSelectedIndex(index); getItemPosition(index); }; // 渲染部分 return ( <View style={{ flex: 1 }}> <FlatList ref={flatlistRef} data={Array(10).fill(1)} removeClippedSubviews={false} CellRendererComponent={({children}) => children} renderItem={({item, index}) => ( <Items key={index} id={`item-${index}`} index={index} onPress={() => onItemPress(index)} isSelected={false} // 原列表里的Item不用高亮 /> )} showsVerticalScrollIndicator={false} /> {openContextMenu ? ( <> <BlurView style={styles.absolute} blurType="light" blurAmount={10} reducedTransparencyFallbackColor="white"> </BlurView> {/* 渲染选中的Item在最上层 */} {selectedItemRect && ( <Items index={selectedIndex} isSelected={true} style={{ position: 'absolute', left: selectedItemRect.x, top: selectedItemRect.y, width: selectedItemRect.width, height: selectedItemRect.height, zIndex: 2, }} /> )} </> ) : null} </View> );
为啥原来不行?
- React Native里
zIndex只在同一个父容器里管用,FlatList和BlurView是同级,后渲染的BlurView默认层级更高,FlatList里的Item再怎么调zIndex也突破不了FlatList本身的层级; - FlatList继承自ScrollView,内部容器默认是
overflow: hidden,子组件出不去,所以就算zIndex设得再高,也会被FlatList的边界截断; - 把Item放FlatList外面时,它和BlurView是同级,zIndex直接控制层级,所以就好使了。
内容的提问来源于stack exchange,提问作者aashik hameed
相关产品推荐
相关产品推荐

