React Native SafeAreaView background color - How to assign two different background color for top and bottom of the screen?
Asked Answered
D

12

84

I'm using SafeAreaView from React Native 0.50.1 and it's working pretty good except for the one part. I assigned the orange background color to the SafrAreaView but can't figure out to change the bottom unsafe area background to black.

Here is the code and I included expected the result and actual result. What is the best way to make the bottom part of the screen black instead of orange?

import {
  ...
  SafeAreaView
} from 'react-native';
class Main extends React.Component {
  render() {
    return (
      <SafeAreaView style={styles.safeArea}>
        <App />
      </SafeAreaView>
    )
  }
}
const styles = StyleSheet.create({
  ...,
  safeArea: {
    flex: 1,
    backgroundColor: '#FF5236'
  }
})

I want to have orange top and black bottom.

But below is what I get now.

Dogmatic answered 9/12, 2017 at 5:29 Comment(1)
Any luck coming up with a solution for this?Geisler
K
167

I was able to solve this using a version of Yoshiki's and Zach Schneider's answers. Notice how you set the top SafeAreaView's flex:0 so it doesn't expand.

render() {
  return (
    <Fragment>
      <SafeAreaView style={{ flex:0, backgroundColor: 'red' }} />
      <SafeAreaView style={{ flex:1, backgroundColor: 'gray' }}>
        <View style={{ flex: 1, backgroundColor: 'white' }} />
      </SafeAreaView>
    </Fragment>
  );
}

enter image description here

Keramic answered 22/9, 2018 at 16:54 Comment(7)
This solution is by far the best, it should be the recognized answer to this question.Rounders
What is the role of flex: 0 in the first safeareaview?Monandrous
You can short syntax Fragment component with empty tags: <></>Kalin
This example looks to not be working anymore. The gray part is now just below the red one, then the white content.Sergeant
🚀 Rocket science. Thanks!Toilette
SOLUTION : I ran into this problem but I don't understand the struggle you guys had to solve it. The app is in a container that takes all the screen. SafeAreaView will wrap the app into a new smaller container. So add the style into the main container so you can have the background you want. As easy as that : <View style={{flex:1, backgroundColor: "black"}}> <SafeAreaView style={{flex:1, backgroundColor: "white"}}> <App /> </SafeAreaView> </View> That's all, hope it helps some of you ;)Letrice
This is the greatest thing ever. I Googled this thinking like, "no way I find out how to do this", and here it is. Thank you!Cowberry
R
26

In 2022, I am able to solve this by using edges prop of SafeAreaView!

import { SafeAreaView } from 'react-native-safe-area-context';

<>
  <SafeAreaView
     edges={["top"]}
     style={{ flex: 0, backgroundColor: "#0a2352" }}
  />
  <SafeAreaView
     edges={["left", "right", "bottom"]}
     style={{
       flex: 1,
       backgroundColor: "#fff",
       position: "relative",
     }}
  >
    ...
  </SafeAreaView>
</>
Rambutan answered 22/3, 2022 at 8:38 Comment(4)
very nice touchLiveryman
also has to add in App.js import {SafeAreaProvider} from 'react-native-safe-area-context'; at rootBooker
Is believe this is for "react-native-safe-area-context", not the "native" SafeAreaView?Shoemake
@Shoemake yup! I added import statement about that. Thanks!Rambutan
S
8

I was able to solve this by using some absolute position hacking. See the following tweak. Not future proof by any means, but it solves the problem I had.

import {
  ...
  SafeAreaView,
  View
} from 'react-native';
class Main extends React.Component {
  render() {
    return (
      <SafeAreaView style={styles.safeArea}>
        <App />
        <View style={styles.fixBackground} />
      </SafeAreaView>
    )
  }
}
const styles = StyleSheet.create({
  ...,
  safeArea: {
    flex: 1,
    backgroundColor: '#FF5236'
  },
  fixBackground: {
    backgroundColor: 'orange',
    position: 'absolute',
    bottom: 0,
    right: 0,
    left: 0,
    height: 100,
    zIndex: -1000,
  }
})
Si answered 17/12, 2017 at 11:59 Comment(0)
K
8

I ran into the same problem and was able to solve with the following:

const styles = StyleSheet.create({
  outerWrapper: {
    backgroundColor: 'orange',
  },
  innerWrapper: {
    backgroundColor: 'black',
  },
});

// snip

const MyComponent = ({ content }) => (
  <View style={styles.outerWrapper}>
    <SafeAreaView />

    <SafeAreaView style={styles.innerWrapper}>
      {content}
    </SafeAreaView>
  </View>
);

The outerWrapper applies the orange background color at the top. The first <SafeAreaView /> pushes the second one down so that it starts at the beginning of the "safe area" (below the status bar). Then the second SafeAreaView takes up the rest of the screen (including the bottom "unsafe" area) and gives it the black background color.

Kei answered 1/6, 2018 at 18:5 Comment(0)
L
7

SOLUTION : I ran into this problem but I don't understand the struggle you guys had to solve it. The app is in a container that takes all the screen. SafeAreaView will wrap the app into a new smaller container. So add the style into the main container so you can have the background you want. As easy as that :

<View style={{flex:1, backgroundColor: "black"}}>
  <SafeAreaView style={{flex:1, backgroundColor: "white"}}>
    <App />
  </SafeAreaView>
</View>

That's all, hope it helps some of you ;)

Letrice answered 6/10, 2021 at 22:55 Comment(1)
This is it. So easy!Whinny
A
5

You can return multiple SafeAreaViews from your render method using Fragment, each of which independently specify their backgroundColor:

render = () => (
  <Fragment>
    <SafeAreaView style={{ flex: 0.5, backgroundColor: "red" }} />
    <SafeAreaView style={{ flex: 0.5, backgroundColor: "blue" }} />
  </Fragment>
);

Result on an iPhone X:

enter image description here

Anticathode answered 26/8, 2018 at 17:44 Comment(0)
D
1

If you need different color of SafeAreaView's top or bottom bar, just cover the bar with View component (positioned absolute) and get its height from useSafeAreaInsets hook.

import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context'
            
<SafeAreaView style={{ flex: 1 }}>
   <View style={{ 
      position: 'absolute'
      height: useSafeAreaInsets().top, 
      backgroundColor:'red'            
    }} />
</SafeAreaView>
Disciplinarian answered 29/7, 2022 at 17:22 Comment(0)
G
0

<Fragment> not work correctly on any Android devices, so to solve the issue, i try this solution and it work on both android and ios:

<SafeAreaView style={{ flex:1, backgroundColor: 'red' }}>
 <View style={{ flex: 1, backgroundColor: 'green' }} >
 <Text>Hello</Text>
 </View>
</SafeAreaView>
Gabardine answered 20/4, 2022 at 12:7 Comment(0)
I
0

The only way that worked for me using expo sdk49 was:

<>
  <SafeAreaView style={{flex: 0, backgroundColor: 'red' }} />
  <View style={{flex: 1, backgroundColor: 'black' }}>
    <App/>
  </View>
</>
Immaterial answered 22/9, 2023 at 20:20 Comment(0)
V
0

For better control, just sandwich your content between two SafeAreaViews with flex-0 and the edges property:

import { SafeAreaView, View } from 'react-native';

<>
    <SafeAreaView edges={["top"]} style={{ flex: 0, backgroundColor: "#0a2352" }} />

    <View style={{ flex: 1 }} >
        ... your content ....
    </View>

    <SafeAreaView edges={["bottom"]} style={{ flex: 0, backgroundColor: "#ffffff" }} />
</>
Viperous answered 28/2 at 15:18 Comment(0)
M
-1

I just ran into the same problem, we have a navigation bar at the top and a tab bar at the bottom with two different background colors.

My solution was to wrap the tab bar component in a SafeAreaView with the correct background color, along with wrapping the navigation bar component with its own SafeAreaView with its background color.

return (
  <SafeAreaView style={{ backgroundColor: 'white' }}>
    <Animated.View style={heightAnim}>
      {...navBarComponentStuff}
    </Animated.View>
  </SafeAreaView>)

For the Navigation Bar

And this for the Tab Bar:

<SafeAreaView style={this.props.tabBarStyle}> //Some dark grey color is passed here
  <Animated.View style={heightAnim}>
    {tabBarItems.map(render tabs.....}
  </Animated.View>
</SafeAreaView>}

So, that being said, you could wrap your navigation component in a SafeAreaView with the orange color set in style, and wrap your main content in another SafeAreaView with black as the backgroundColor style, or whatever color you have chosen.

One thing you should know, if you add two SafeAreaView's in the same component like:

return (
  <View style={styles.container}>
    <SafeAreaView style={{ backgroundColor: 'white' }}>
      <NavigationBarComponent />
    </SafeAreaView>
    <SafeAreaView style={this.props.tabBarStyle}>
      <Animated.View style={heightAnim}>
        <Animated.View style={[styles.tabBar, this.props.tabBarStyle]}>
          {map and render tabs}
        </Animated.View>
      </Animated.View>
    </SafeAreaView>
  </View>
);

It will combine the two SafeAreaView's, or at least thats what it looked like to me, maybe somebody with more experience with this can explain what happens in this situation.

This pushed my tab bar to the top of the screen and set the background color to white when I did this.

But moving the top SafeAreaVeiw into the NavigationBarComponent gave me the desired effect.

For those who may be interested, and maybe this is the reason why it acted funky with two of them in the same view, the AnimatedView's are because we sometimes hide the nav and tab bars.

Marlysmarmaduke answered 1/5, 2018 at 21:35 Comment(0)
A
-2

I was able to achieve this by the code below,

<View style={{
    flex: 1
}}>
  <SafeAreaView style={{
    flex: 0,
    backgroundColor: 'red'
  }}>
  </SafeAreaView>
  <View style={{
      flex: 1,
      top: 0,
      backgroundColor: 'white'
   }}>
  </View></View>

Thanks for @Daniel M, inspired by his answer.

Antoneantonella answered 8/5, 2019 at 8:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.