如何防止布局与iOS状态栏重叠

107
我正在为React Native导航 tutorial 工作。我发现所有布局都从屏幕顶部开始加载,而不是从状态栏下面开始。这会导致大多数布局与状态栏重叠。我可以通过在加载它们时向视图添加填充来解决此问题。这是实际的解决方法吗?我认为手动添加填充不是一个真正的解决方法。是否有更优雅的方法来解决这个问题?
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> 
            )   
    }    
}

以下显示了添加填充前后的屏幕截图。 enter image description here

16
好的问题,但也许你可以缩减图片。 - Quv
这个答案不仅可以解决在此处提到的问题,还可以让您有可能在iOS和Android中着色状态栏的背景。 - Martin Braun
10个回答

78

现在您可以使用 React Navigation 中包含的 SafeAreaView

<SafeAreaView>
    ... your content ...
</SafeAreaView>

4
可能需要注意的是,现在默认情况下react-navigation已经包含了这个组件。 - Aᴄʜᴇʀᴏɴғᴀɪʟ
34
这并没有解决状态栏重叠的问题——我在我的应用程序中使用了SafeAreaView,但我的应用程序仍然会与StatusBar重叠。它似乎更适用于iPhone X的刘海屏/圆角情况。 - izikandrw
1
你不需要将整个应用程序包装在其中,而是将一个屏幕包装在其中。 - Greg Ennis
1
@AndreFigueiredo 不正确。只要是iOS 11以上的所有iPhone设备都可以正常工作。 - Fellow Stranger
@FellowStranger 你说得对。它不仅适用于iPhone X。 - Andre Figueiredo
显示剩余2条评论

42

有一个非常简单的方法来解决这个问题,那就是创建一个组件。

你可以创建一个 StatusBar 组件,并在父组件中第一次视图包装器之后首先调用它。

以下是我使用的代码:

'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
做完这个并将其导出到您的主组件后,可以这样调用它:

完成此操作并将其导出到您的主组件后,可以像这样调用它:

import StatusBarBackground from './YourPath/StatusBarBackground'

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

 

 


"MidnightBlue" 是无效的,React Native 提示:警告:传递了无效的 backgroundColor 属性 - Raptor
2
它应该是 midnightblue - bblincoe
24
iOS 状态栏的大小不是固定的。在共享 Wifi 或通话时,它可能会变得更大。 - edA-qa mort-ora-y
1
当使用React Navigation与Redux连接时,我该如何使用它?所有页面都在堆栈导航器或选项卡导航器(嵌套)中,并与Redux连接。 - Yasir
5
如果您导入React Native组件“StatusBar”,然后使用以下代码:height: (Platform.OS === 'ios') ? 20 : StatusBar.currentHeight,而不是 ? 20 : 0,,则在Android上可以获得相同的结果。 - mrroot5
@edA-qamort-ora-y True ... 在5.5英寸的显示屏上(物理像素为56 / 3 displayPixelRatio = 18px)或iPhoneX上(物理像素为132 / 3 = 44px),加上20px始终是错误的。 - Jules

34

我尝试了一种更简单的方法。

我们可以获取 Android 系统状态栏的高度,并使用 SafeAreaView 与其配合,使代码在两个平台上都能正常工作。

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

如果我们记录Platform.OSStatusBar.currentHeight,我们将得到日志,

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

在 Android 24 上的高度以及在 Android 24 上的高度。

我们现在可以选择地使用 margin/padding 向容器视图添加间距/填充。

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

App.js中的最终代码如下:

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
  }
});

1
我已经在安卓设备上测试过了,运行正常。我还没在iOS设备上测试过,但是因为我知道iOS上的SafeArea是什么,所以我相信它应该在那里也能正常工作。 - manuelwaldner
1
这应该被设置为已接受的答案。 其他解决方案提供基于其自己的单个测试情况的任意固定高度。 - rosmcmahon
2
一个完美的答案,但是SafeAreaView不适用于iPhone设备版本低于11。 - Pradeep
工作得很好。谢谢! - bruxo00
最好的一个。有效的。我们为什么要在这里检查iOS? - sarfrazanwar

17

@philipheinser的解决方案确实有效。

然而,我希望React Native的StatusBar组件能够为我们处理这个问题。

不幸的是,它没有做到,但我们可以通过创建自己的组件来轻松地将其抽象出来:

./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>
    )
}


6
react-navigation 的文档提供了一个很好的解决方案。首先,他们建议不要使用 React Native 自带的 SafeAreaView,因为:

虽然 React Native 导出了 SafeAreaView 组件,但它存在一些固有问题,例如,如果包含安全区域的屏幕正在进行动画,会导致跳动行为。此外,该组件仅支持 iOS 10+,而不支持旧版 iOS 或 Android。我们建议使用 react-native-safe-area-context 库以更可靠的方式处理安全区域。

相反,他们建议使用 react-native-safe-area-context——它将看起来像这样:

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> 
    )   
}

我想指出,使用这个库提供的 SafeAreaView 可能是一个更好的选择,因为现在的手机可能会有一些元素在底部重叠 UI 元素。当然,这完全取决于你的应用程序。(如果需要更多详细信息,请参阅我在开头提供的 react-navigation 文档。)


2
此内容已过时。 - Acauã Pitta
2
@AcauãPitta 在提出主张时,请提供来源。 - AndyO
1
根据文档,useSafeArea 已被弃用: https://github.com/th3rdwave/react-native-safe-area-context#usesafearea。建议使用 useSafeAreaInsets 钩子。 - Guilherme Samuel
如果您需要更多的灵活性,请使用此钩子,但是如果不需要,就像您所说的那样,使用SafeAreaView和SafeAreaProvider作为最清洁的解决方案。 - Guilherme Samuel

2

2

以下是适用于iOS的方法:

<View style={{height: 20, backgroundColor: 'white', marginTop: -20, zIndex: 2}}>
   <StatusBar barStyle="dark-content"/></View>

0
你可以通过为导航栏组件添加填充或者在视图树的顶部添加一个与状态栏相同高度且背景颜色类似于 Facebook 应用程序的视图来处理此问题。

6
那个高度数值是固定的吗?不管你用什么类型的手机都不会改变吗?如果是这样,我应该在哪里找到有关iOS/Android正确特定数值的信息? - nbkhope

0

[此答案适用于Android模拟器] 您好,我从“react-native”导入了状态栏,并在块的末尾调用它,将状态栏样式设置为自动,这对我很有效。以下是参考代码:

    import { SafeAreaView,Button, StyleSheet, Text, TextInput, View } from 'react-native';
    import { StatusBar } from 'react-native';
    export default function App() {
    return (
<SafeAreaView style={styles.appContainer}>
  
  
  <View >
    <TextInput placeholder='Add your course goal' />
    <Button title="Add Goals" />
  </View>
  <View>
  <Text>List of goals..</Text>
  </View>
  <StatusBar style="auto" />
  </SafeAreaView>
   );
   }

0
只需简单地使用 React Native 的默认 StatusBar 就可以实现这个功能。
<View style={styles.container}>
    <StatusBar backgroundColor={Color.TRANSPARENT} translucent={true} />
    <MapView
      provider={PROVIDER_GOOGLE} // remove if not using Google Maps
      style={styles.map}
      region={{
        latitude: 37.78825,
        longitude: -122.4324,
        latitudeDelta: 0.015,
        longitudeDelta: 0.0121,
      }}
    />
  </View>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接