Add statusBarBackgroundColor to DrawerLayoutAndroid to allow it to open over the status bar

Summary:The navigation drawer of most apps on android opens over the status bar, this adds an option to do so. It implements a similar API to the native DrawerLayout by adding a statusBarBackgroundColor to DrawerLayoutAndroid.

Without statusBarBackgroundColor:
![image](https://cloud.githubusercontent.com/assets/2677334/13414490/50ebcdf4-df21-11e5-974f-c6a1343c2a4e.png)

With statusBarBackgroundColor:
![image](https://cloud.githubusercontent.com/assets/2677334/13414459/1fdc4086-df21-11e5-9658-bd47bfdb925f.png)

This PR depends on the changes in #6195 to add the `StatusBar.HEIGHT` constant I just want to put it out there now to see if this looks good. To test without the other PR just change `StatusBar.HEIGHT` for `25`.

It is implemented by making the native status bar translucent and making its background color transparent so we can draw a view of the same height as the status bar under it as a child of the DrawerLayoutAndroid. Then we can draw a semi-transparent gray View inside the drawer view to make it
Closes https://github.com/facebook/react-native/pull/6218

Differential Revision: D3017444

Pulled By: bestander

fb-gh-sync-id: ca48a47a20a2feecae360a76f3e2c9bbe6a37700
fbshipit-source-id: ca48a47a20a2feecae360a76f3e2c9bbe6a37700
This commit is contained in:
Janic Duplessis 2016-03-30 05:29:10 -07:00 committed by Facebook Github Bot 6
parent 5bbf88be5a
commit 039924ec70
2 changed files with 79 additions and 22 deletions

View File

@ -71,7 +71,8 @@ class UIExplorerApp extends React.Component {
this._overrideBackPressForDrawerLayout = false; this._overrideBackPressForDrawerLayout = false;
}} }}
ref={(drawer) => { this.drawer = drawer; }} ref={(drawer) => { this.drawer = drawer; }}
renderNavigationView={this._renderDrawerContent.bind(this, onNavigate)}> renderNavigationView={this._renderDrawerContent.bind(this, onNavigate)}
statusBarBackgroundColor="#589c90">
{this._renderNavigation(navigationState, onNavigate)} {this._renderNavigation(navigationState, onNavigate)}
</DrawerLayoutAndroid> </DrawerLayoutAndroid>
); );
@ -79,6 +80,7 @@ class UIExplorerApp extends React.Component {
_renderDrawerContent(onNavigate) { _renderDrawerContent(onNavigate) {
return ( return (
<View style={styles.drawerContentWrapper}>
<UIExplorerExampleList <UIExplorerExampleList
list={UIExplorerList} list={UIExplorerList}
displayTitleRow={true} displayTitleRow={true}
@ -88,6 +90,7 @@ class UIExplorerApp extends React.Component {
onNavigate(action); onNavigate(action);
}} }}
/> />
</View>
); );
} }
@ -113,9 +116,6 @@ class UIExplorerApp extends React.Component {
const ExampleComponent = UIExplorerExampleList.makeRenderable(ExampleModule); const ExampleComponent = UIExplorerExampleList.makeRenderable(ExampleModule);
return ( return (
<View style={styles.container}> <View style={styles.container}>
<StatusBar
backgroundColor="#589c90"
/>
<ToolbarAndroid <ToolbarAndroid
logo={require('image!launcher_icon')} logo={require('image!launcher_icon')}
navIcon={require('image!ic_menu_black_24dp')} navIcon={require('image!ic_menu_black_24dp')}
@ -131,9 +131,6 @@ class UIExplorerApp extends React.Component {
} }
return ( return (
<View style={styles.container}> <View style={styles.container}>
<StatusBar
backgroundColor="#589c90"
/>
<ToolbarAndroid <ToolbarAndroid
logo={require('image!launcher_icon')} logo={require('image!launcher_icon')}
navIcon={require('image!ic_menu_black_24dp')} navIcon={require('image!ic_menu_black_24dp')}
@ -181,6 +178,10 @@ const styles = StyleSheet.create({
backgroundColor: '#E9EAED', backgroundColor: '#E9EAED',
height: 56, height: 56,
}, },
drawerContentWrapper: {
paddingTop: StatusBar.currentHeight,
backgroundColor: 'white',
},
}); });
AppRegistry.registerComponent('UIExplorerApp', () => UIExplorerApp); AppRegistry.registerComponent('UIExplorerApp', () => UIExplorerApp);

View File

@ -10,9 +10,12 @@
*/ */
'use strict'; 'use strict';
var ColorPropType = require('ColorPropType');
var NativeMethodsMixin = require('NativeMethodsMixin'); var NativeMethodsMixin = require('NativeMethodsMixin');
var Platform = require('Platform');
var React = require('React'); var React = require('React');
var ReactPropTypes = require('ReactPropTypes'); var ReactPropTypes = require('ReactPropTypes');
var StatusBar = require('StatusBar');
var StyleSheet = require('StyleSheet'); var StyleSheet = require('StyleSheet');
var UIManager = require('UIManager'); var UIManager = require('UIManager');
var View = require('View'); var View = require('View');
@ -25,12 +28,6 @@ var requireNativeComponent = require('requireNativeComponent');
var RK_DRAWER_REF = 'drawerlayout'; var RK_DRAWER_REF = 'drawerlayout';
var INNERVIEW_REF = 'innerView'; var INNERVIEW_REF = 'innerView';
var DrawerLayoutValidAttributes = {
drawerWidth: true,
drawerPosition: true,
drawerLockMode: true
};
var DRAWER_STATES = [ var DRAWER_STATES = [
'Idle', 'Idle',
'Dragging', 'Dragging',
@ -132,21 +129,52 @@ var DrawerLayoutAndroid = React.createClass({
* The navigation view that will be rendered to the side of the screen and can be pulled in. * The navigation view that will be rendered to the side of the screen and can be pulled in.
*/ */
renderNavigationView: ReactPropTypes.func.isRequired, renderNavigationView: ReactPropTypes.func.isRequired,
/**
* Make the drawer take the entire screen and draw the background of the
* status bar to allow it to open over the status bar. It will only have an
* effect on API 21+.
*/
statusBarBackgroundColor: ColorPropType,
}, },
mixins: [NativeMethodsMixin], mixins: [NativeMethodsMixin],
getInitialState: function() {
return {statusBarBackgroundColor: undefined};
},
getInnerViewNode: function() { getInnerViewNode: function() {
return this.refs[INNERVIEW_REF].getInnerViewNode(); return this.refs[INNERVIEW_REF].getInnerViewNode();
}, },
componentDidMount: function() {
this._updateStatusBarBackground();
},
componentDidReceiveProps: function() {
this._updateStatusBarBackground();
},
render: function() { render: function() {
var drawStatusBar = Platform.Version >= 21 && this.props.statusBarBackgroundColor;
var drawerViewWrapper = var drawerViewWrapper =
<View style={[styles.drawerSubview, {width: this.props.drawerWidth}]} collapsable={false}> <View style={[styles.drawerSubview, {width: this.props.drawerWidth}]} collapsable={false}>
{this.props.renderNavigationView()} {this.props.renderNavigationView()}
{drawStatusBar && <View style={styles.drawerStatusBar} />}
</View>; </View>;
var childrenWrapper = var childrenWrapper =
<View ref={INNERVIEW_REF} style={styles.mainSubview} collapsable={false}> <View ref={INNERVIEW_REF} style={styles.mainSubview} collapsable={false}>
{drawStatusBar &&
<StatusBar
translucent
backgroundColor={this.state.statusBarBackgroundColor}
/>}
{drawStatusBar &&
<View style={[
styles.statusBar,
{backgroundColor: this.props.statusBarBackgroundColor}
]} />}
{this.props.children} {this.props.children}
</View>; </View>;
return ( return (
@ -213,6 +241,23 @@ var DrawerLayoutAndroid = React.createClass({
_getDrawerLayoutHandle: function() { _getDrawerLayoutHandle: function() {
return React.findNodeHandle(this.refs[RK_DRAWER_REF]); return React.findNodeHandle(this.refs[RK_DRAWER_REF]);
}, },
// Update the StatusBar component background color one frame after creating the
// status bar background View to avoid a white flicker that happens because
// the StatusBar background becomes transparent before the status bar View
// from this component has rendered.
_updateStatusBarBackground: function() {
if (Platform.Version >= 21 && this.props.statusBarBackgroundColor) {
// Check if the value is not already transparent to avoid an extra render.
if (this.state.statusBarBackgroundColor !== 'transparent') {
requestAnimationFrame(() => {
this.setState({statusBarBackgroundColor: 'transparent'});
});
}
} else {
this.setState({statusBarBackgroundColor: undefined});
}
},
}); });
var styles = StyleSheet.create({ var styles = StyleSheet.create({
@ -233,6 +278,17 @@ var styles = StyleSheet.create({
bottom: 0, bottom: 0,
backgroundColor: 'white', backgroundColor: 'white',
}, },
statusBar: {
height: StatusBar.currentHeight,
},
drawerStatusBar: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
height: StatusBar.currentHeight,
backgroundColor: 'rgba(0, 0, 0, 0.251)',
},
}); });
// The View that contains both the actual drawer and the main view // The View that contains both the actual drawer and the main view