前言

沉浸式标题栏,简单来说,即是透明栏,标题栏和状态栏不再是传统的黑色或白色,而是透明的,使得手机应用界面占据整个屏幕空间,页面从上向下滚动时,状态栏和标题内容慢慢由透明变成不透明,退出沉浸模式。以上交互,主要通过设置状态栏 StatusBar 和 透明度 opacity 来实现。

设置 opacity

初始情况下,标题栏和状态栏的透明度opacity为0,页面向下滚动一段距离(这里设定为标题栏的高度)后,其透明度一点点的由0变为1。
基本思路是:
const opacity = 滚动的距离 / 标题栏的高度
完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import React, {PureComponent} from 'react'
import { View, Text, ScrollView } from 'react-native'
import TitleBar from '../../components/TitleBar'

export default class TitlePage extends PureComponent {
constructor(props) {
super(props)
this.state = {
titleBarHeight: 50 // 顶部标题栏的高度
}
// 顶部标题栏
this.titleBarView = null
}

// 监听列表滚动事件
scrollViewScroll = (event) => {
const y = event.nativeEvent.contentOffset.y
// 设置标题栏和状态栏的透明度 titleOpacity
// 当页面滚动的距离等于标题栏的高度时,其透明度变为1
const scale = y * 1.0 / this.state.titleBarHeight
this.titleBarView.setState({
titleOpacity: scale,
})
}

render() {
const { titleBarHeight} = this.state
return (
<View>
{/*沉浸式标题*/}
<TitleBar
onRef={(ref) => this.titleBarView = ref}
titleBarHeight={titleBarHeight}
/>
<ScrollView
onScroll={this.scrollViewScroll}
>
<Text>页面内容</Text>
</ScrollView>
</View>
)
}
}

设置 StatusBar

在 ios 端,状态栏默认是沉浸式的默认情况下, View 的内容会从屏幕顶部开始绘制;在 android 端,状态栏会遮住主题内容,需设置状态栏是否透明

  • barStyle 设置状态栏文本的颜色
  • translucent 指定状态栏是否透明。设置为true时,应用会在状态栏之下绘制(即所谓“沉浸式”)– android
  • backgroundColor 状态栏背景色 – android
1
2
3
4
5
6
7
8
9
10
11
12
13
_renderStatusBar = () => {
const { titleOpacity } = this.state
const backgroundColor = `rgba(0, 0, 0, ${titleOpacity})`
if (Platform.OS === 'ios') {
return <StatusBar barStyle={'dark-content'}/>
} else if (Platform.OS === 'android') {
return <StatusBar
backgroundColor={backgroundColor}
barStyle={'dark-content'}
translucent={true}/>
}
return null
}

设置标题栏

  • 整个标题栏的高度应该等于状态栏的高度 statusBarHeight 加上 标题模块的高度 titleBarHeight
    获取状态栏的高度:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    import { Platform, NativeModules } from "react-native"
    const { StatusBarManager } = NativeModules
    // 获取状态栏的高度
    const getStatusBarHeight = () => {
    return new Promise((resolve) => {
    const OS = Platform.OS
    if (OS === 'ios') {
    StatusBarManager.getHeight(statusBarHeight => {
    resolve(statusBarHeight)
    })
    } else if (OS === 'android') {
    resolve(StatusBarManager || {}).HEIGHT || 0
    }
    resolve(0)
    })

    }
    let statusBarHeight = 0
    getStatusBarHeight().then((res) => {
    statusBarHeight = res
    })
  • 标题栏需设置成 absolute 定位,这样标题栏展示在手机主体内容上层,使得主体内容占据整个屏幕空间

完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import React, {PureComponent} from 'react'
import {
View,
StatusBar,
StyleSheet,
Platform
} from 'react-native'
import { statusBarHeight } from '../common/globalData'

export default class TitleBar extends PureComponent {
constructor(props) {
super(props)
this.props.onRef(this)
this.state = {
// 背景透明度
titleOpacity: 0
}
}
_renderStatusBar = () => {
const { titleOpacity } = this.state
const backgroundColor = `rgba(0, 0, 0, ${titleOpacity})`
if (Platform.OS === 'ios') {
return <StatusBar barStyle={'dark-content'}/>
} else if (Platform.OS === 'android') {
return <StatusBar
backgroundColor={backgroundColor}
barStyle={'dark-content'}
translucent={true}/>
}
return null
}
render() {
const { titleBarHeight } = this.props
const { titleOpacity } = this.state
return (
<View style={[{height: titleBarHeight + statusBarHeight}, TitleStyle.titleBarWrapper]}>
{this._renderStatusBar()}
<View style={[TitleStyle.titleBarBg, {
opacity: titleOpacity,
}]}/>
<View style={[TitleStyle.titleBarContent, {
marginTop: statusBarHeight,
height: titleBarHeight
}]}>
{/* 标题栏主题内容*/}
</View>
</View>
)
}
}

const TitleStyle = StyleSheet.create({
titleBarWrapper: {
flexDirection: 'row',
position: 'absolute',
top: 0,
zIndex: 100,
width: '100%'
},
titleBarContent: {
alignItems: 'center',
justifyContent: 'center',
width: '100%',
height: 50,
},
titleBarBg: {
position: 'absolute',
top: 0,
height: '100%',
width: '100%',
backgroundColor: '#fff',
}
})