最近臨時做下react native的項目開發(fā),有個功能點是這樣:在一個選項卡組件里(用了ScrollView郊闯,其中放置Tab組件)咬腋,做一個縱向時間軸效果(用Tab組件里放置Flatlist組件)轿腺。點擊不同的選項卡,定位到具體時間軸上的數(shù)據(jù)歹嘹。示意圖如下:
image.png
一般時間軸可以用Flatlist組件來實現(xiàn),github上這個老哥開源的組件就相當(dāng)好用:https://github.com/thegamenicorus/react-native-timeline-listview孔庭。不過他這個是基于ListView的尺上,可以找下Flatlist的相關(guān)實現(xiàn)。
各個組件之間層級示意圖:
image.png
說回正題圆到,準(zhǔn)確跳轉(zhuǎn)的這個難點在于怎抛,ScrollView和Flatlist是同一方向的滾動(由上往下滾動),所以直接調(diào)用Flatlist的 scrollToItem芽淡、scrollToIndex可能沒效果马绝。即使有效果,也是在Flatlist上滾動挣菲,外層的ScorllView可能無法滾動到準(zhǔn)確位置富稻。
想了個解決方法,在時間軸組件里白胀,每行數(shù)據(jù)渲染的時候椭赋,將該行高度存起來。當(dāng)選項卡組件點擊不同的選項卡時或杠,調(diào)用時間軸里自定義的方法哪怔,將要滾動的總高度(0..n行總共高度)回傳給選項卡組件,調(diào)用Scrollview的scrollTo進(jìn)行滾動向抢。
具體各個組件改動如下蔓涧。
CustomTimelineFlat(自定義的時間軸組件)
this.state.flatListHeight //在state里聲明一個用來存儲每行index和該行最終高度的關(guān)系的Map
//每行render的時候,在onLayout方法里笋额,將高度和該行index存入
return <View key={rowID}
onLayout = {(event) => {
const {
x,
y,
width,
height
} = event.nativeEvent.layout;
let old = this.state.flatListHeight
console.warn('onLayout '+JSON.stringify(old))
old[index] = height
this.setState({
flatListHeight:old
})
}}
>{content}</View>;
//自定義一個方法供外部調(diào)用元暴,返回0..n行的總高度
scrollTo(index){
console.warn('in CusttomTimeLineFlat index '+index)
let all = 0
//使用比index小的index對應(yīng)的高度進(jìn)行疊加
for(let i = 0; i < index; i++) {
all += this.state.flatListHeight[i]
}
console.warn('after flatListRef scorll,all is '+all)
return all
}
ScorllView和Tab的頁面里的代碼示例如下:
//在SrollView初始化時聲明該組件的ref
<ScrollView
ref={c => (this.detailScrollRef = c)}
stickyHeaderIndices={[0]}
nestedScrollEnabled={true}
>
其中放置了Tab組件。
…
</ScorllView>
//初始化時間軸組件兄猩,聲明該組件的ref供外部調(diào)用
<CustomTimelineFlat
ref={c => (this.detailTimelineRef = c)}
data={eventList}
/>
//當(dāng)點擊選項卡時茉盏,調(diào)用下面這個方法,使頁面滾動到具體的某行
handleSubTabChange(subTab){
let y = 0
switch(subTab){
case 21:
y = this.detailTimelineRef.scrollTo(0)
break;
case 22:
y = this.detailTimelineRef.scrollTo(1)
break
default:
y = height/2
break;
}
//調(diào)用ScrollView的ref進(jìn)行滾動
this.detailScrollRef.scrollTo({x:0,y:y,animated:true})
}
至此大功告成枢冤。