众所周知:FlatList 是基于 ScrollView 封装的,底层都是 VirtualizedList 组件。安卓端是有提示的:ScrollView和FlatList是禁止嵌套的。
先上布局,最终做出来的显示页面如下:

简单分析下布局:整个页面是可以下拉刷新的,日历是吸顶的一个横向可滚动的FlatList,下面内容区域:左侧是可滚动的列表,右侧也是可滚动的列表。右侧滚动下拉时,如果是触顶了,也可以触发整个页面的下拉刷新。右侧列表的顶部又是一小块可横向滚动的标签列表。
刚接到这个稿子是崩溃的,试了很多方案都不行,特别是在安卓机器上,低端安卓机上挺让人崩溃的。此处忽略尝试过的N种方案(尝试过很多用定位的方案)
本方案的核心绊脚石是页面的下拉刷新,难就难在这,由于它的存在,导致了滚动容器必须内外嵌套。
直接说下最终的处理方案:安卓上实在是难以兼容各种低端机型,下拉刷新直接放右上角点击刷新(有点蠢),ios上的布局处理,页面最外层用的是ScrollView,内部左侧和右侧都是用的ScrollView组件。
页面最外层的scrollEnabled 通过变量来控制,当内部左侧或者右侧滚动容器触顶的时候,把变量开关打开,则外侧容易可滚动,下拉结束之后立刻关闭变量。
<ScrollView
scrollEnabled={flatListScrollEnable}
bounces={true}
alwaysBounceVertical={false}
style={styles.flatWrap}
refreshControl={<ZTRefreshControl
ref={ref => this.innerModel._refreshControl = ref}
refreshing={isRefreshing}
onRefresh={() => {
this.onRefresh()
}}
stateLabelColor={'#fff'}
loadingStyleName={"white"}
/>}
showsVerticalScrollIndicator={false}
keyExtractor={(item, index) => index.toString()}
stickyHeaderIndices={[0]}
scrollEventThrottle={1}
onMomentumScrollEnd={(event) => {
if (flatListScrollEnable) {
setState({ flatListScrollEnable: false })
}
}}
>
{/* 左侧列表 */}
<ScrollView
bounces={isIos}
onScroll={() => {
Animated.event(
[{}],
{
listener: (event) => {
const yOffset = event?.nativeEvent?.contentOffset?.y;
if (yOffset <= 1) {
if (!flatListScrollEnable) {
scrollEnable()
}
} else {
if (flatListScrollEnable) {
scrollInhibit()
}
}
}
})
}}
style={styles.scrollWrap}
showsVerticalScrollIndicator={false}
>
{/* 内容列表 */}
</ScrollView >
{/* 右侧也如此 */}
<ScrollView
bounces={isIos}
onScroll={() => {
Animated.event(
[{}],
{
listener: (event) => {
const yOffset = event?.nativeEvent?.contentOffset?.y;
if (yOffset <= 1) {
if (!flatListScrollEnable) {
scrollEnable()
}
} else {
if (flatListScrollEnable) {
scrollInhibit()
}
}
}
})
}}
style={styles.scrollWrap}
showsVerticalScrollIndicator={false}
>
{/* 内容列表 */}
</ScrollView >
</ScrollView>
也曾尝试过通过监听手势来处理,但是触顶之后的弹性根本不会触发手势响应。很是令人头疼,以上方案也是自己琢磨尝试出来的结果。
该页面为 ios app 智行火车票 智慧出行搜索结果页。
如果您有更好的处理这类布局的方案,还请不吝赐教!
