Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent layout from overlapping with iOS status bar

I am working on tutorial for React Native navigation. I found out that all layout starts loading from top of screen instead of below of the status bar. This causes most layouts to overlap with the status bar. I can fix this by adding a padding to the view when loading them. Is this the actual way to do it? I don' think manually adding padding is an actual way to solve it. Is there a more elegant way to fix this?

import React, { Component } from 'react';
import { View, Text, Navigator } from 'react-native';

export default class MyScene extends Component {
    static get defaultProps() {
            return {
                    title : 'MyScene'    
            };  
    }   
    render() {
            return (
                    <View style={{padding: 20}}> //padding to prevent overlap
                            <Text>Hi! My name is {this.props.title}.</Text>
                    </View> 
            )   
    }    
}

Below shows the screenshots before and after the padding is added. enter image description here

like image 579
Cliff Avatar asked Mar 04 '17 18:03

Cliff


People also ask

How can I change my status bar in Android like iPhone?

Just launch Xblast Tools and navigate to Status Bar -> Clock Settings -> Center clock. After a quick reboot, your status bar will be looking very similar to an iPhone's. (1) Status bar on iOS 8. (2) Android status bar with iOS 8 Killer.

How do I stop the status bar in react native?

React Native StatusBar Props It is used to hide and show the status bar. By default, it is false. If hidden = {false} it is visible, if hidden = {true}, it hide the status bar.

How do I get the StatusBar height in react native?

currentHeight : import {StatusBar} from 'react-native'; console. log('statusBarHeight: ', StatusBar. currentHeight);


6 Answers

Now you can use SafeAreaView which is included in React Navigation:

<SafeAreaView>
    ... your content ...
</SafeAreaView>
like image 64
Greg Ennis Avatar answered Oct 06 '22 01:10

Greg Ennis


There is a very simple way to fix this. Make a component.

You can create a StatusBar component and call it first after the first view wrapper in your parent components.

Here is the code for the one I use:

'use strict'
import React, {Component} from 'react';
import {View, Text, StyleSheet, Platform} from 'react-native';

class StatusBarBackground extends Component{
  render(){
    return(
      <View style={[styles.statusBarBackground, this.props.style || {}]}> //This part is just so you can change the color of the status bar from the parents by passing it as a prop
      </View>
    );
  }
}

const styles = StyleSheet.create({
  statusBarBackground: {
    height: (Platform.OS === 'ios') ? 18 : 0, //this is just to test if the platform is iOS to give it a height of 18, else, no height (Android apps have their own status bar)
    backgroundColor: "white",
  }

})

module.exports= StatusBarBackground

After doing this and exporting it to your main component, call it like this:

import StatusBarBackground from './YourPath/StatusBarBackground'

export default class MyScene extends Component {
  render(){
    return(
      <View>
        <StatusBarBackground style={{backgroundColor:'midnightblue'}}/>
      </View>
    )
  }
}

 

like image 27
Luis Rizo Avatar answered Oct 06 '22 00:10

Luis Rizo


I tried a more simple way for this.

We can get the height of Status Bar on android and use SafeAreaView along with it to make the code work on both platforms.

import { SafeAreaView, StatusBar, Platform } from 'react-native';

If we log out Platform.OS and StatusBar.currentHeight we get the logs,

console.log('Height on: ', Platform.OS, StatusBar.currentHeight);

Height on: android 24 and Height on: android 24

We can now optionally add margin/padding to our container view using

paddingTop: Platform.OS === "android" ? StatusBar.currentHeight : 0

The final code in App.js is below:

export default class App extends React.Component {
  render() {
    return (
      <SafeAreaView style={{ flex: 1, backgroundColor: "#fff" }}>
        <View style={styles.container}>
          <Text>Hello World</Text>
        </View>
      </SafeAreaView>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    paddingTop: Platform.OS === "android" ? StatusBar.currentHeight : 0
  }
});
like image 21
Gaurav Saluja Avatar answered Oct 06 '22 01:10

Gaurav Saluja


@philipheinser solution does work indeed.

However, I would expect that React Native's StatusBar component will handle that for us.

It doesn't, unfortunately, but we can abstract that away quite easily by creating our own component around it:

./StatusBar.js

import React from 'react';
import { View, StatusBar, Platform } from 'react-native';

// here, we add the spacing for iOS
// and pass the rest of the props to React Native's StatusBar

export default function (props) {
    const height = (Platform.OS === 'ios') ? 20 : 0;
    const { backgroundColor } = props;

    return (
        <View style={{ height, backgroundColor }}>
            <StatusBar { ...props } />
        </View>
    );
}

./index.js

import React from 'react';
import { View } from 'react-native';

import StatusBar from './StatusBar';

export default function App () {
    return (
      <View>
        <StatusBar backgroundColor="#2EBD6B" barStyle="light-content" />
        { /* rest of our app */ }
      </View>
    )
}
Before:

After:

like image 35
Asaf Katz Avatar answered Oct 06 '22 01:10

Asaf Katz


The react-navigation docs have a great solution for this. First off, they recommend not to use the SafeAreaView included with React Native because:

While React Native exports a SafeAreaView component, it has some inherent issues, i.e. if a screen containing safe area is animating, it causes jumpy behavior. In addition, this component only supports iOS 10+ with no support for older iOS versions or Android. We recommend to use the react-native-safe-area-context library to handle safe areas in a more reliable way.

Instead, they recommend react-native-safe-area-context - with which it would look like this:

import React, { Component } from 'react';
import { View, Text, Navigator } from 'react-native';
import { useSafeArea } from 'react-native-safe-area-context';

export default function MyScene({title = 'MyScene'}) {
    const insets = useSafeArea();

    return (
        <View style={{paddingTop: insets.top}}>
            <Text>Hi! My name is {title}.</Text>
        </View> 
    )   
}

I would like to note that it's probably a better idea to use the SafeAreaView that this library offers though, since phones these days may also have elements at the bottom that can overlap UI elements. It all depends on your app of course. (For more detail on that, see the react-navigation docs I linked to in the beginning.)

like image 45
AndyO Avatar answered Oct 05 '22 23:10

AndyO


Here is a way that works for iOS:

<View style={{height: 20, backgroundColor: 'white', marginTop: -20, zIndex: 2}}>
   <StatusBar barStyle="dark-content"/></View>
like image 23
edu_shin Avatar answered Oct 06 '22 00:10

edu_shin