2 Different Background Colours For ScrollView bounce
I wouldn't play with the contentInset
and contentOffset
of the ScrollView as if your content changes, it might change the position of your scrollview.
You can do something very simple by just adding a View at the very top of your ScrollView:
// const spacerHeight = 1000;
<ScrollView>
{Platform.OS === 'ios' && (
<View
style={{
backgroundColor: 'red',
height: spacerHeight,
position: 'absolute',
top: -spacerHeight,
left: 0,
right: 0,
}}
/>
)}
</ScrollView>
On iOS, you can render a spacer View
on top of the ScrollView
, and use contentInset
to render it "off-screen", contentOffset
to set the initial scroll position to offset the inset:
render() {
const isIos = Platform.OS === 'ios'
const SPACER_SIZE = 1000; //arbitrary size
const TOP_COLOR = 'white';
const BOTTOM_COLOR = 'papayawhip';
return (
<ScrollView
style={{backgroundColor: isIos ? BOTTOM_COLOR : TOP_COLOR }}
contentContainerStyle={{backgroundColor: TOP_COLOR}}
contentInset={{top: -SPACER_SIZE}}
contentOffset={{y: SPACER_SIZE}}>
{isIos && <View style={{height: SPACER_SIZE}} />}
//...your content here
</ScrollView>
);
}
Because contentInset
and contentOffset
are iOS only, this example is conditioned to degrade gracefully on Android.
The accepted solution did not work well for me because I need to put flexGrow: 1
on the contentContainerStyle. Using insets/offsets didn't make the content grow the way I want, otherwise it worked not so bad.
I have another solution to suggest: putting a bicolor background layer under a transparent ScrollView, and add colors to your scrollview content. This way, on ios bounce, the bicolor layer under the scrollview will reveal itself.
Here's what I mean by bicolor layer (here the scrollview is empty and transparent)
Now if I put back the ScrollView children (which if a body with blank background, and a footer with yellow background), I get this:
As long as you don't bounce more than 50% of the scrollview height, you will see the appropriate background color.
Here's a component you can use to wrap your scrollview.
const AppScrollViewIOSBounceColorsWrapper = ({
topBounceColor,
bottomBounceColor,
children,
...props
}) => {
return (
<View {...props} style={[{ position: 'relative' }, props.style]}>
{children}
<View
style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
zIndex: -1, // appear under the scrollview
}}
>
<View
style={{ flex: 1, backgroundColor: topBounceColor }}
/>
<View
style={{ flex: 1, backgroundColor: bottomBounceColor }}
/>
</View>
</View>
);
};
And here's how you use it:
<AppScrollViewIOSBounceColorsWrapper
style={{flex: 1}}
topBounceColor="white"
bottomBounceColor="yellowLancey"
>
<ScrollView style={{flex: 1}}>
<WhiteBackgroundBody/>
<YellowBackgroundFooter />
</AppScrollView>
</AppScrollViewIOSBounceColorsWrapper>
Make sure to NOT set a background color to the scrollview, otherwise the bicolor layer will never reveal itself (backgroundColor on contentContainerStyle is fine)
For me, the simplest solution is modification based on Sebastien Lorber answer which doesn't include wrapping, just calling it before (or after) ScrollView component:
Create component:
interface IScrollViewBackgroundLayer {
topBounceColor: string;
bottomBounceColor: string;
}
export const ScrollViewBackgroundLayer = ({
topBounceColor,
bottomBounceColor,
}: IScrollViewBackgroundLayer): ReactElement => (
<View
style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
zIndex: -1, // appear under the scrollview
}}>
<View style={{ flex: 1, backgroundColor: topBounceColor }} />
<View style={{ flex: 1, backgroundColor: bottomBounceColor }} />
</View>
);
and use it like this:
return (
<SafeAreaView style={styles.container}>
<ScrollViewBackgroundLayer topBounceColor={topBounceColor} bottomBounceColor={bottomBounceColor} />
<ScrollView>
...
</ScrollView>
</SafeAreaView>