From 039924ec7039dfa21d26e388a2f800c7138f9d4c Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Wed, 30 Mar 2016 05:29:10 -0700 Subject: [PATCH] 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 --- Examples/UIExplorer/UIExplorerApp.android.js | 33 ++++----- .../DrawerLayoutAndroid.android.js | 68 +++++++++++++++++-- 2 files changed, 79 insertions(+), 22 deletions(-) diff --git a/Examples/UIExplorer/UIExplorerApp.android.js b/Examples/UIExplorer/UIExplorerApp.android.js index 026567bf5..2488def43 100644 --- a/Examples/UIExplorer/UIExplorerApp.android.js +++ b/Examples/UIExplorer/UIExplorerApp.android.js @@ -71,7 +71,8 @@ class UIExplorerApp extends React.Component { this._overrideBackPressForDrawerLayout = false; }} ref={(drawer) => { this.drawer = drawer; }} - renderNavigationView={this._renderDrawerContent.bind(this, onNavigate)}> + renderNavigationView={this._renderDrawerContent.bind(this, onNavigate)} + statusBarBackgroundColor="#589c90"> {this._renderNavigation(navigationState, onNavigate)} ); @@ -79,15 +80,17 @@ class UIExplorerApp extends React.Component { _renderDrawerContent(onNavigate) { return ( - { - this.drawer && this.drawer.closeDrawer(); - onNavigate(action); - }} - /> + + { + this.drawer && this.drawer.closeDrawer(); + onNavigate(action); + }} + /> + ); } @@ -113,9 +116,6 @@ class UIExplorerApp extends React.Component { const ExampleComponent = UIExplorerExampleList.makeRenderable(ExampleModule); return ( - - UIExplorerApp); diff --git a/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js b/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js index 4be589ab7..a381a7819 100644 --- a/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js +++ b/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js @@ -10,9 +10,12 @@ */ 'use strict'; +var ColorPropType = require('ColorPropType'); var NativeMethodsMixin = require('NativeMethodsMixin'); +var Platform = require('Platform'); var React = require('React'); var ReactPropTypes = require('ReactPropTypes'); +var StatusBar = require('StatusBar'); var StyleSheet = require('StyleSheet'); var UIManager = require('UIManager'); var View = require('View'); @@ -25,12 +28,6 @@ var requireNativeComponent = require('requireNativeComponent'); var RK_DRAWER_REF = 'drawerlayout'; var INNERVIEW_REF = 'innerView'; -var DrawerLayoutValidAttributes = { - drawerWidth: true, - drawerPosition: true, - drawerLockMode: true -}; - var DRAWER_STATES = [ 'Idle', '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. */ 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], + getInitialState: function() { + return {statusBarBackgroundColor: undefined}; + }, + getInnerViewNode: function() { return this.refs[INNERVIEW_REF].getInnerViewNode(); }, + componentDidMount: function() { + this._updateStatusBarBackground(); + }, + + componentDidReceiveProps: function() { + this._updateStatusBarBackground(); + }, + render: function() { + var drawStatusBar = Platform.Version >= 21 && this.props.statusBarBackgroundColor; var drawerViewWrapper = {this.props.renderNavigationView()} + {drawStatusBar && } ; var childrenWrapper = + {drawStatusBar && + } + {drawStatusBar && + } {this.props.children} ; return ( @@ -213,6 +241,23 @@ var DrawerLayoutAndroid = React.createClass({ _getDrawerLayoutHandle: function() { 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({ @@ -233,6 +278,17 @@ var styles = StyleSheet.create({ bottom: 0, 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