Add imperative API to StatusBar

Reviewed By: svcscm

Differential Revision: D2938743

fb-gh-sync-id: 30af304efd5b089854d9a8defc1b77fd8e817d13
shipit-source-id: 30af304efd5b089854d9a8defc1b77fd8e817d13
This commit is contained in:
Janic Duplessis 2016-02-16 03:04:16 -08:00 committed by facebook-github-bot-8
parent 9a918ef48f
commit edbe6a2b24
3 changed files with 212 additions and 39 deletions

View File

@ -57,12 +57,16 @@ const showHideTransitions = [
'slide',
];
function getValue(values: Array<any>, index: number): any {
return values[index % values.length];
}
const StatusBarExample = React.createClass({
getInitialState(): State {
return {
animated: true,
backgroundColor: this._getValue(colors, 0),
showHideTransition: this._getValue(showHideTransitions, 0),
backgroundColor: getValue(colors, 0),
showHideTransition: getValue(showHideTransitions, 0),
};
},
@ -70,10 +74,6 @@ const StatusBarExample = React.createClass({
_barStyleIndex: 0,
_showHideTransitionIndex: 0,
_getValue(values: Array<any>, index: number): any {
return values[index % values.length];
},
render() {
return (
<View>
@ -110,10 +110,10 @@ const StatusBarExample = React.createClass({
style={styles.wrapper}
onPress={() => {
this._barStyleIndex++;
this.setState({barStyle: this._getValue(barStyles, this._barStyleIndex)});
this.setState({barStyle: getValue(barStyles, this._barStyleIndex)});
}}>
<View style={styles.button}>
<Text>style: '{this._getValue(barStyles, this._barStyleIndex)}'</Text>
<Text>style: '{getValue(barStyles, this._barStyleIndex)}'</Text>
</View>
</TouchableHighlight>
</View>
@ -138,13 +138,13 @@ const StatusBarExample = React.createClass({
this._showHideTransitionIndex++;
this.setState({
showHideTransition:
this._getValue(showHideTransitions, this._showHideTransitionIndex),
getValue(showHideTransitions, this._showHideTransitionIndex),
});
}}>
<View style={styles.button}>
<Text>
showHideTransition:
'{this._getValue(showHideTransitions, this._showHideTransitionIndex)}'
'{getValue(showHideTransitions, this._showHideTransitionIndex)}'
</Text>
</View>
</TouchableHighlight>
@ -155,10 +155,10 @@ const StatusBarExample = React.createClass({
style={styles.wrapper}
onPress={() => {
this._colorIndex++;
this.setState({backgroundColor: this._getValue(colors, this._colorIndex)});
this.setState({backgroundColor: getValue(colors, this._colorIndex)});
}}>
<View style={styles.button}>
<Text>backgroundColor: '{this._getValue(colors, this._colorIndex)}'</Text>
<Text>backgroundColor: '{getValue(colors, this._colorIndex)}'</Text>
</View>
</TouchableHighlight>
</View>
@ -181,11 +181,116 @@ const StatusBarExample = React.createClass({
},
});
const StatusBarStaticExample = React.createClass({
_colorIndex: 0,
_barStyleIndex: 0,
_showHideTransitionIndex: 0,
getInitialState() {
return {
backgroundColor: getValue(colors, 0),
barStyle: getValue(barStyles, 0),
hidden: false,
networkActivityIndicatorVisible: false,
translucent: false,
};
},
render() {
return (
<View>
<View>
<TouchableHighlight
style={styles.wrapper}
onPress={() => {
const hidden = !this.state.hidden;
StatusBar.setHidden(hidden, 'slide');
this.setState({hidden});
}}>
<View style={styles.button}>
<Text>hidden: {this.state.hidden ? 'true' : 'false'}</Text>
</View>
</TouchableHighlight>
</View>
<Text style={styles.title}>iOS</Text>
<View>
<TouchableHighlight
style={styles.wrapper}
onPress={() => {
this._barStyleIndex++;
const barStyle = getValue(barStyles, this._barStyleIndex);
StatusBar.setBarStyle(barStyle, true);
this.setState({barStyle});
}}>
<View style={styles.button}>
<Text>style: '{getValue(barStyles, this._barStyleIndex)}'</Text>
</View>
</TouchableHighlight>
</View>
<View>
<TouchableHighlight
style={styles.wrapper}
onPress={() => {
const networkActivityIndicatorVisible = !this.state.networkActivityIndicatorVisible;
StatusBar.setNetworkActivityIndicatorVisible(networkActivityIndicatorVisible);
this.setState({networkActivityIndicatorVisible});
}}>
<View style={styles.button}>
<Text>
networkActivityIndicatorVisible:
{this.state.networkActivityIndicatorVisible ? 'true' : 'false'}
</Text>
</View>
</TouchableHighlight>
</View>
<Text style={styles.title}>Android</Text>
<View>
<TouchableHighlight
style={styles.wrapper}
onPress={() => {
this._colorIndex++;
const backgroundColor = getValue(colors, this._colorIndex);
StatusBar.setBackgroundColor(backgroundColor, true);
this.setState({backgroundColor});
}}>
<View style={styles.button}>
<Text>backgroundColor: '{getValue(colors, this._colorIndex)}'</Text>
</View>
</TouchableHighlight>
</View>
<View>
<TouchableHighlight
style={styles.wrapper}
onPress={() => {
const translucent = !this.state.translucent;
const backgroundColor = !this.state.translucent ? 'rgba(0, 0, 0, 0.4)' : 'black';
StatusBar.setTranslucent(translucent);
StatusBar.setBackgroundColor(backgroundColor, true);
this.setState({
translucent,
backgroundColor,
});
}}>
<View style={styles.button}>
<Text>translucent: {this.state.translucent ? 'true' : 'false'}</Text>
</View>
</TouchableHighlight>
</View>
</View>
);
},
});
exports.examples = [{
title: 'Status Bar',
title: 'StatusBar',
render() {
return <StatusBarExample />;
},
}, {
title: 'StatusBar static API',
render() {
return <StatusBarStaticExample />;
},
}];
var styles = StyleSheet.create({

View File

@ -19,6 +19,17 @@ const processColor = require('processColor');
const StatusBarManager = require('NativeModules').StatusBarManager;
export type StatusBarStyle = $Enum<{
'default': string,
'light-content': string,
}>;
export type StatusBarAnimation = $Enum<{
'none': string,
'fade': string,
'slide': string,
}>;
type DefaultProps = {
animated: boolean;
};
@ -26,16 +37,10 @@ type DefaultProps = {
/**
* Merges the prop stack with the default values.
*/
function mergePropsStack(propsStack: Array<Object>): Object {
function mergePropsStack(propsStack: Array<Object>, defaultValues: Object): Object {
return propsStack.reduce((prev, cur) => {
return Object.assign(prev, cur);
}, {
backgroundColor: 'black',
barStyle: 'default',
translucent: false,
hidden: false,
networkActivityIndicatorVisible: false,
});
}, defaultValues);
}
/**
@ -64,10 +69,75 @@ function mergePropsStack(propsStack: Array<Object>): Object {
* />
* </View>
* ```
*
* ### Imperative API
*
* For cases where using a component is not ideal, there is also an imperative
* API exposed as static functions on the component. It is however not recommended
* to use the static API and the compoment for the same prop because any value
* set by the static API will get overriden by the one set by the component in
* the next render.
*/
const StatusBar = React.createClass({
statics: {
_propsStack: [],
_defaultProps: {
backgroundColor: 'black',
barStyle: 'default',
translucent: false,
hidden: false,
networkActivityIndicatorVisible: false,
},
// Provide an imperative API as static functions of the component.
// See the corresponding prop for more detail.
setHidden(hidden: boolean, animation?: StatusBarAnimation) {
animation = animation || 'none';
StatusBar._defaultProps.hidden = hidden;
if (Platform.OS === 'ios') {
StatusBarManager.setHidden(hidden, animation);
} else if (Platform.OS === 'android') {
StatusBarManager.setHidden(hidden);
}
},
setBarStyle(style: StatusBarStyle, animated?: boolean) {
if (Platform.OS !== 'ios') {
console.warn('`setBarStyle` is only available on iOS');
return;
}
animated = animated || false;
StatusBar._defaultProps.barStyle = style;
StatusBarManager.setStyle(style, animated);
},
setNetworkActivityIndicatorVisible(visible: boolean) {
if (Platform.OS !== 'ios') {
console.warn('`setNetworkActivityIndicatorVisible` is only available on iOS');
return;
}
StatusBar._defaultProps.networkActivityIndicatorVisible = visible;
StatusBarManager.setNetworkActivityIndicatorVisible(visible);
},
setBackgroundColor(color, animated?: boolean) {
if (Platform.OS !== 'android') {
console.warn('`setBackgroundColor` is only available on Android');
return;
}
animated = animated || false;
StatusBar._defaultProps.backgroundColor = color;
StatusBarManager.setColor(processColor(color), animated);
},
setTranslucent(translucent: boolean) {
if (Platform.OS !== 'android') {
console.warn('`setTranslucent` is only available on Android');
return;
}
StatusBar._defaultProps.translucent = translucent;
StatusBarManager.setTranslucent(translucent);
},
},
propTypes: {
@ -156,7 +226,7 @@ const StatusBar = React.createClass({
* Updates the native status bar with the props from the stack.
*/
_updatePropsStack() {
const mergedProps = mergePropsStack(StatusBar._propsStack);
const mergedProps = mergePropsStack(StatusBar._propsStack, StatusBar._defaultProps);
if (Platform.OS === 'ios') {
if (mergedProps.barStyle !== undefined) {

View File

@ -11,33 +11,31 @@
*/
'use strict';
var RCTStatusBarManager = require('NativeModules').StatusBarManager;
const StatusBar = require('StatusBar');
type StatusBarStyle = $Enum<{
'default': string,
'light-content': string,
}>;
import type {StatusBarStyle, StatusBarAnimation} from 'StatusBar';
type StatusBarAnimation = $Enum<{
'none': string,
'fade': string,
'slide': string,
}>;
var StatusBarIOS = {
/**
* Deprecated. Use `StatusBar` instead.
*/
const StatusBarIOS = {
setStyle(style: StatusBarStyle, animated?: boolean) {
animated = animated || false;
RCTStatusBarManager.setStyle(style, animated);
console.warn('`StatusBarIOS.setStyle` is deprecated. Use `StatusBar.setBarStyle` instead.');
StatusBar.setBarStyle(style, animated);
},
setHidden(hidden: boolean, animation?: StatusBarAnimation) {
animation = animation || 'none';
RCTStatusBarManager.setHidden(hidden, animation);
console.warn('`StatusBarIOS.setHidden` is deprecated. Use `StatusBar.setHidden` instead.');
StatusBar.setHidden(hidden, animation);
},
setNetworkActivityIndicatorVisible(visible: boolean) {
RCTStatusBarManager.setNetworkActivityIndicatorVisible(visible);
console.warn(
'`StatusBarIOS.setNetworkActivityIndicatorVisible` is deprecated. ' +
'Use `StatusBar.setNetworkActivityIndicatorVisible` instead.'
);
StatusBar.setNetworkActivityIndicatorVisible(visible);
},
};