反应本机: 使用 ScrollView 时垂直居中

我正在使用反应本机,我有麻烦保持垂直中心的元素,只要我引入一个 ScrollView。为了演示,我使用 React Natural Playground 创建了3个应用程序。所有的例子有2页,他们可以通过点击蓝色按钮切换。

例子一:

第一个示例显示在第2页上垂直居中的块。之所以会发生这种情况,是因为容器应用了以下样式:

flex: 1,
flexDirection: 'column',
justifyContent: 'center',

Https://rnplay.org/apps/lb5wsq

但是,一旦切换到第2页,就会出现一个问题,因为页面的整个内容不适合,所以我们需要一个 ScrollView

例子2

在本例中,我将所有内容都包装在 ScrollView 中。这允许第2页滚动,但现在我失去了第1页的垂直中心。

Https://rnplay.org/apps/dcgoga

例子3

为了尝试回到第1页的垂直中心,我将 flex: 1应用到 ScrollView 的 contentContainerStyle。这修复了第1页的垂直中心,但是我不再能够一直向下滚动到第2页的底部。

Https://rnplay.org/apps/lsgbog

我怎样才能修正这个问题,使我得到垂直居中的元素在第1页,但仍然得到 ScrollView 滚动所有的方式到底部的第2页?

68956 次浏览

Why don't you wrap only second page within a ScrollView?

return (
<ScrollView >
<View style={styles.lipsum}>
{this.renderButton()}
<Text style={styles.lipsumText}>{lipsumText}</Text>
</View>
</ScrollView>
);

Just modify your first example, it works like a charm :)

EDIT: You can now use <ScrollView contentContainerStyle=\{\{flexGrow: 1}}>.

For older version of React Native that do not support flexGrow, use the solution below.


The only way I have found to reliably do this for both iOS and Android is to set minHeight of the inner view to the size of the ScrollView. E.g:

<ScrollView
style=\{\{flex: 1}}
contentContainerStyle=\{\{minHeight: this.state.minHeight}}
onLayout={event => this.setState({minHeight: event.nativeEvent.layout.height})}
>

Note: I have in-lined the styles and functions above for simplicity but you will probably want to use constant references for the unchanging values and memorise the changing style to prevent unnecessary rerenders.

const {minHeight} = this.state;
// Manually memorise changing style or use something like reselect...
if (this.lastMinHeight != minHeight) {
this.lastMinHeight = minHeight;
this.contentContainerStyle = {minHeight: minHeight}
}
<ScrollView
style={styles.scrollViewStyle}
contentContainerStyle={this.contentContainerStyle}
onLayout={this.onScrollViewLayout}
>

There's a new solution (unfortunately iOS only at the moment) - we can use centerContent prop on Scrollview.

I solved this issue with flexGrow instead of flex

<ScrollView contentContainerStyle=\{\{ flexGrow: 1, justifyContent: 'center' }}>

This makes the content container stretch to fill the ScrollView but does not restrict the maximum height, so you can still scroll correctly when the content extends the bounds of the ScrollView

Here is my approach:

Use an outer container with flex : 1, then the scroll view needs to have {flexGrow : 1, justifyContent : 'center'} using contentContainerStyle, not style.

<View style={styles.mainContainer}>
<ScrollView
contentContainerStyle=\{\{flexGrow : 1, justifyContent : 'center'}}>
<View style={styles.scrollViewContainer}>
//Put your stuff here, and it will be centered vertical
</View>
</ScrollView>
</View>

Styles:

const styles = StyleSheet.create({scrollView : {
height : Dimensions.get('window').height, }, mainContainer : {
flex : 1 }, scrollViewContainer : { }, })

In order to center ScrollView itself vertically, then you need to have such kind of structure:

<View style=\{\{flex: 1}}>
<View>
<ScrollView .../>
</View>
</View>

Otherwise, if you want to center ScrollView content itself, then you need the following:

<ScrollView contentContainerStyle=\{\{flexGrow : 1, justifyContent : 'center'}} ...>

Set flexGrow to 1 for ScrollView contentContainerStyle

<ScrollView contentContainerStyle=\{\{ flexGrow: 1, justifyContent: 'center' }}>