市面上有相應的插件 react-native-collapsible, 但它在摺疊狀態底部有莫名其妙的空白,且有很多bug未解決, 於是自己試着實現了一個簡版。
基礎結構
<View style={S.container}>
<View style={{flex: 1}}>
<View style={S.content}
onLayout={this.onContentLayout}>
{ this.props.children }
</View>
</View>
</View>
const S = StyleSheet.create({
container: {
overflow: 'hidden'
},
content: {
position: 'absolute',
top: 0,
left: 0,
right: 0
}
})
我們需要能動態控制顯示高度,會用到overflow:hidden
,而默認狀態是摺疊的,因此,爲了獲取實際內容的真實高度(不固定),需加兩層嵌套,以便通過onLayout
方法提前得到展開後的高度。
這是開啓動畫的前提。
動畫的實現
這裏介紹兩種方式
Animated Component
這是我常用的技巧。首先把container
裏面的元素用Animated.View
封裝:
<Animated.View style={{ height: this.state.height }}>
<View style={{flex: 1}}>
...
</View>
</Animated.View>
其中height
初值爲new Animated.Value(0)
,數值0表示完全摺疊。
然後當展開時,給height
應用動畫即可:
Animated.timing(
this.state.height,
{
toValue: newHeight,
duration: this.props.duration || 300,
easing: this.props.easing || Easing.linear
}
).start()
這裏newHeight
爲新的高度值,比如第一步中通過onLayout
得到的真實高度。
反之亦然,摺疊時,再設爲0即可。
LayoutAnimation
這是從reactnativecode.com上學到的技巧,原作者不詳。
這種方法不需要再次封裝,代碼相對簡潔得多。這回我們直接在container
上設置height
:
<View style={[ S.container, { height: this.state.height } ]}>
...
</View>
然後當摺疊或展開時,設定動畫並更新高度值:
LayoutAnimation.configureNext( LayoutAnimation.Presets.easeInEaseOut )
this.setState({ height: newHeight })
注意事項
在安卓機上,需要手動開啓動畫:
if ( Platform.OS === 'android' ) {
UIManager.setLayoutAnimationEnabledExperimental(true)
}
踩坑
安卓下內容溢出
儘管設置了overflow:hidden
,安卓下內容仍然會溢出一部分,然後和下方的內容層疊了,醜爆。
不能說overflow無效,但又不完全符合預期,試了多種方法包括改結構,均無效,太認人沮喪了。
爲了方便調試,就加了背景色,居然好了。莫名其妙的就好了!
所以解決方法是——設定背景色。
over