前言
沉浸式标题栏,简单来说,即是透明栏,标题栏和状态栏不再是传统的黑色或白色,而是透明的,使得手机应用界面占据整个屏幕空间,页面从上向下滚动时,状态栏和标题内容慢慢由透明变成不透明,退出沉浸模式。以上交互,主要通过设置状态栏 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 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', } })
|