眾所周知: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 智行火車票 智慧出行搜索結果頁。
如果您有更好的處理這類布局的方案,還請不吝賜教!