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)

enter image description here

Now if I put back the ScrollView children (which if a body with blank background, and a footer with yellow background), I get this:

enter image description here

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>