mirror of
https://github.com/status-im/react-native.git
synced 2025-02-04 13:44:04 +00:00
Add StatusBar height constant and improve implementation
Summary:This adds a `HEIGHT` constant on `StatusBar` on Android. I needed only this for now but I will work on a better status bar dimensions API later (see TODO). It also improves the implementation to fix a bug that happened when multiple `StatusBar` components get updated in the same frame as well as remove useless calls to the `StatusBarModule` when values did not change. Instead of calling the `StatusBarManager` immediately when the component gets updated and relying on the order of the calls that get dispatched to native we now wait at the end of the frame to send the calls to the `StatusBarManager` using `setImmediate`. To make this work properly we need to change the data structure of the props stack a little bit to store the desired transition/animation too for each value. Finally this updates the example to only show the ones that work for the current platform. **Test plan** In the UIExplorer Example, in the 'StatusBar dimensions' section it should show 25 for the height of the status bar. A Closes https://github.com/facebook/react-native/pull/6195 Differential Revision: D3017559 fb-gh-sync-id: d6f4c6a72a2dfde83496ecc0f56dca4abaf3055e shipit-source-id: d6f4c6a72a2dfde83496ecc0f56dca4abaf3055e
This commit is contained in:
parent
d0caf7e48b
commit
18f38ecdc0
@ -17,26 +17,13 @@
|
||||
|
||||
const React = require('react-native');
|
||||
const {
|
||||
StatusBar,
|
||||
StyleSheet,
|
||||
View,
|
||||
Text,
|
||||
TouchableHighlight,
|
||||
StatusBar,
|
||||
View,
|
||||
} = React;
|
||||
|
||||
type BarStyle = 'default' | 'light-content';
|
||||
type ShowHideTransition = 'fade' | 'slide';
|
||||
|
||||
type State = {
|
||||
animated: boolean,
|
||||
backgroundColor: string,
|
||||
hidden?: boolean,
|
||||
showHideTransition: ShowHideTransition,
|
||||
translucent?: boolean,
|
||||
barStyle?: BarStyle,
|
||||
networkActivityIndicatorVisible?: boolean
|
||||
};
|
||||
|
||||
exports.framework = 'React';
|
||||
exports.title = '<StatusBar>';
|
||||
exports.description = 'Component for controlling the status bar';
|
||||
@ -57,242 +44,412 @@ const showHideTransitions = [
|
||||
'slide',
|
||||
];
|
||||
|
||||
function getValue(values: Array<any>, index: number): any {
|
||||
function getValue<T>(values: Array<T>, index: number): T {
|
||||
return values[index % values.length];
|
||||
}
|
||||
|
||||
const StatusBarExample = React.createClass({
|
||||
getInitialState(): State {
|
||||
const StatusBarHiddenExample = React.createClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
animated: true,
|
||||
backgroundColor: getValue(colors, 0),
|
||||
hidden: false,
|
||||
showHideTransition: getValue(showHideTransitions, 0),
|
||||
};
|
||||
},
|
||||
|
||||
_colorIndex: 0,
|
||||
_barStyleIndex: 0,
|
||||
_showHideTransitionIndex: 0,
|
||||
|
||||
_onChangeAnimated() {
|
||||
this.setState({animated: !this.state.animated});
|
||||
},
|
||||
|
||||
_onChangeHidden() {
|
||||
this.setState({hidden: !this.state.hidden});
|
||||
},
|
||||
|
||||
_onChangeTransition() {
|
||||
this._showHideTransitionIndex++;
|
||||
this.setState({
|
||||
showHideTransition: getValue(showHideTransitions, this._showHideTransitionIndex),
|
||||
});
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<StatusBar
|
||||
hidden={this.state.hidden}
|
||||
showHideTransition={this.state.showHideTransition}
|
||||
animated={this.state.animated}
|
||||
/>
|
||||
<TouchableHighlight
|
||||
style={styles.wrapper}
|
||||
onPress={this._onChangeHidden}>
|
||||
<View style={styles.button}>
|
||||
<Text>hidden: {this.state.hidden ? 'true' : 'false'}</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
<TouchableHighlight
|
||||
style={styles.wrapper}
|
||||
onPress={this._onChangeAnimated}>
|
||||
<View style={styles.button}>
|
||||
<Text>animated (ios only): {this.state.animated ? 'true' : 'false'}</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
<TouchableHighlight
|
||||
style={styles.wrapper}
|
||||
onPress={this._onChangeTransition}>
|
||||
<View style={styles.button}>
|
||||
<Text>
|
||||
showHideTransition (ios only):
|
||||
'{getValue(showHideTransitions, this._showHideTransitionIndex)}'
|
||||
</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
const StatusBarStyleExample = React.createClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
animated: true,
|
||||
barStyle: getValue(barStyles, this._barStyleIndex),
|
||||
};
|
||||
},
|
||||
|
||||
_barStyleIndex: 0,
|
||||
|
||||
_onChangeBarStyle() {
|
||||
this._barStyleIndex++;
|
||||
this.setState({barStyle: getValue(barStyles, this._barStyleIndex)});
|
||||
},
|
||||
|
||||
_onChangeAnimated() {
|
||||
this.setState({animated: !this.state.animated});
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<StatusBar
|
||||
animated={this.state.animated}
|
||||
barStyle={this.state.barStyle}
|
||||
/>
|
||||
<TouchableHighlight
|
||||
style={styles.wrapper}
|
||||
onPress={this._onChangeBarStyle}>
|
||||
<View style={styles.button}>
|
||||
<Text>style: '{getValue(barStyles, this._barStyleIndex)}'</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
<TouchableHighlight
|
||||
style={styles.wrapper}
|
||||
onPress={this._onChangeAnimated}>
|
||||
<View style={styles.button}>
|
||||
<Text>animated: {this.state.animated ? 'true' : 'false'}</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
const StatusBarNetworkActivityExample = React.createClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
networkActivityIndicatorVisible: false,
|
||||
};
|
||||
},
|
||||
|
||||
_onChangeNetworkIndicatorVisible() {
|
||||
this.setState({
|
||||
networkActivityIndicatorVisible: !this.state.networkActivityIndicatorVisible,
|
||||
});
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<StatusBar
|
||||
networkActivityIndicatorVisible={this.state.networkActivityIndicatorVisible}
|
||||
/>
|
||||
<TouchableHighlight
|
||||
style={styles.wrapper}
|
||||
onPress={this._onChangeNetworkIndicatorVisible}>
|
||||
<View style={styles.button}>
|
||||
<Text>
|
||||
networkActivityIndicatorVisible:
|
||||
{this.state.networkActivityIndicatorVisible ? 'true' : 'false'}
|
||||
</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
const StatusBarBackgroundColorExample = React.createClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
animated: true,
|
||||
backgroundColor: getValue(colors, 0),
|
||||
};
|
||||
},
|
||||
|
||||
_colorIndex: 0,
|
||||
|
||||
_onChangeBackgroundColor() {
|
||||
this._colorIndex++;
|
||||
this.setState({backgroundColor: getValue(colors, this._colorIndex)});
|
||||
},
|
||||
|
||||
_onChangeAnimated() {
|
||||
this.setState({animated: !this.state.animated});
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<StatusBar
|
||||
backgroundColor={this.state.backgroundColor}
|
||||
translucent={this.state.translucent}
|
||||
hidden={this.state.hidden}
|
||||
showHideTransition={this.state.showHideTransition}
|
||||
animated={this.state.animated}
|
||||
barStyle={this.state.barStyle}
|
||||
networkActivityIndicatorVisible={this.state.networkActivityIndicatorVisible}
|
||||
/>
|
||||
<View>
|
||||
<TouchableHighlight
|
||||
style={styles.wrapper}
|
||||
onPress={() => this.setState({animated: !this.state.animated})}>
|
||||
onPress={this._onChangeBackgroundColor}>
|
||||
<View style={styles.button}>
|
||||
<Text>backgroundColor: '{getValue(colors, this._colorIndex)}'</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
<TouchableHighlight
|
||||
style={styles.wrapper}
|
||||
onPress={this._onChangeAnimated}>
|
||||
<View style={styles.button}>
|
||||
<Text>animated: {this.state.animated ? 'true' : 'false'}</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
</View>
|
||||
<View>
|
||||
<TouchableHighlight
|
||||
style={styles.wrapper}
|
||||
onPress={() => this.setState({hidden: !this.state.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++;
|
||||
this.setState({barStyle: getValue(barStyles, this._barStyleIndex)});
|
||||
}}>
|
||||
<View style={styles.button}>
|
||||
<Text>style: '{getValue(barStyles, this._barStyleIndex)}'</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
</View>
|
||||
<View>
|
||||
<TouchableHighlight
|
||||
style={styles.wrapper}
|
||||
onPress={() => this.setState({
|
||||
networkActivityIndicatorVisible: !this.state.networkActivityIndicatorVisible,
|
||||
})}>
|
||||
<View style={styles.button}>
|
||||
<Text>
|
||||
networkActivityIndicatorVisible:
|
||||
{this.state.networkActivityIndicatorVisible ? 'true' : 'false'}
|
||||
</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
</View>
|
||||
<View>
|
||||
<TouchableHighlight
|
||||
style={styles.wrapper}
|
||||
onPress={() => {
|
||||
this._showHideTransitionIndex++;
|
||||
this.setState({
|
||||
showHideTransition:
|
||||
getValue(showHideTransitions, this._showHideTransitionIndex),
|
||||
});
|
||||
}}>
|
||||
<View style={styles.button}>
|
||||
<Text>
|
||||
showHideTransition:
|
||||
'{getValue(showHideTransitions, this._showHideTransitionIndex)}'
|
||||
</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
</View>
|
||||
<Text style={styles.title}>Android</Text>
|
||||
<View>
|
||||
<TouchableHighlight
|
||||
style={styles.wrapper}
|
||||
onPress={() => {
|
||||
this._colorIndex++;
|
||||
this.setState({backgroundColor: getValue(colors, this._colorIndex)});
|
||||
}}>
|
||||
<View style={styles.button}>
|
||||
<Text>backgroundColor: '{getValue(colors, this._colorIndex)}'</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
</View>
|
||||
<View>
|
||||
<TouchableHighlight
|
||||
style={styles.wrapper}
|
||||
onPress={() => {
|
||||
this.setState({
|
||||
translucent: !this.state.translucent,
|
||||
backgroundColor: !this.state.translucent ? 'rgba(0, 0, 0, 0.4)' : 'black',
|
||||
});
|
||||
}}>
|
||||
<View style={styles.button}>
|
||||
<Text>translucent: {this.state.translucent ? 'true' : 'false'}</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
const StatusBarStaticExample = React.createClass({
|
||||
_colorIndex: 0,
|
||||
_barStyleIndex: 0,
|
||||
_showHideTransitionIndex: 0,
|
||||
|
||||
const StatusBarTranslucentExample = React.createClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
backgroundColor: getValue(colors, 0),
|
||||
barStyle: getValue(barStyles, 0),
|
||||
hidden: false,
|
||||
networkActivityIndicatorVisible: false,
|
||||
translucent: false,
|
||||
};
|
||||
},
|
||||
|
||||
_onChangeTranslucent() {
|
||||
this.setState({
|
||||
translucent: !this.state.translucent,
|
||||
});
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<View>
|
||||
<StatusBar
|
||||
translucent={this.state.translucent}
|
||||
/>
|
||||
<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,
|
||||
});
|
||||
}}>
|
||||
onPress={this._onChangeTranslucent}>
|
||||
<View style={styles.button}>
|
||||
<Text>translucent: {this.state.translucent ? 'true' : 'false'}</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
const StatusBarStaticIOSExample = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<TouchableHighlight
|
||||
style={styles.wrapper}
|
||||
onPress={() => {
|
||||
StatusBar.setHidden(true, 'slide');
|
||||
}}>
|
||||
<View style={styles.button}>
|
||||
<Text>setHidden(true, 'slide')</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
<TouchableHighlight
|
||||
style={styles.wrapper}
|
||||
onPress={() => {
|
||||
StatusBar.setHidden(false, 'fade');
|
||||
}}>
|
||||
<View style={styles.button}>
|
||||
<Text>setHidden(false, 'fade')</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
<TouchableHighlight
|
||||
style={styles.wrapper}
|
||||
onPress={() => {
|
||||
StatusBar.setBarStyle('default', true);
|
||||
}}>
|
||||
<View style={styles.button}>
|
||||
<Text>setBarStyle('default', true)</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
<TouchableHighlight
|
||||
style={styles.wrapper}
|
||||
onPress={() => {
|
||||
StatusBar.setBarStyle('light-content', true);
|
||||
}}>
|
||||
<View style={styles.button}>
|
||||
<Text>setBarStyle('light-content', true)</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
<TouchableHighlight
|
||||
style={styles.wrapper}
|
||||
onPress={() => {
|
||||
StatusBar.setNetworkActivityIndicatorVisible(true);
|
||||
}}>
|
||||
<View style={styles.button}>
|
||||
<Text>setNetworkActivityIndicatorVisible(true)</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
<TouchableHighlight
|
||||
style={styles.wrapper}
|
||||
onPress={() => {
|
||||
StatusBar.setNetworkActivityIndicatorVisible(false);
|
||||
}}>
|
||||
<View style={styles.button}>
|
||||
<Text>setNetworkActivityIndicatorVisible(false)</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
exports.examples = [{
|
||||
title: 'StatusBar',
|
||||
const StatusBarStaticAndroidExample = React.createClass({
|
||||
render() {
|
||||
return <StatusBarExample />;
|
||||
return (
|
||||
<View>
|
||||
<TouchableHighlight
|
||||
style={styles.wrapper}
|
||||
onPress={() => {
|
||||
StatusBar.setHidden(true);
|
||||
}}>
|
||||
<View style={styles.button}>
|
||||
<Text>setHidden(true)</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
<TouchableHighlight
|
||||
style={styles.wrapper}
|
||||
onPress={() => {
|
||||
StatusBar.setHidden(false);
|
||||
}}>
|
||||
<View style={styles.button}>
|
||||
<Text>setHidden(false)</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
<TouchableHighlight
|
||||
style={styles.wrapper}
|
||||
onPress={() => {
|
||||
StatusBar.setBackgroundColor('#ff00ff', true);
|
||||
}}>
|
||||
<View style={styles.button}>
|
||||
<Text>setBackgroundColor('#ff00ff', true)</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
<TouchableHighlight
|
||||
style={styles.wrapper}
|
||||
onPress={() => {
|
||||
StatusBar.setBackgroundColor('#00ff00', true);
|
||||
}}>
|
||||
<View style={styles.button}>
|
||||
<Text>setBackgroundColor('#00ff00', true)</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
<TouchableHighlight
|
||||
style={styles.wrapper}
|
||||
onPress={() => {
|
||||
StatusBar.setTranslucent(true);
|
||||
StatusBar.setBackgroundColor('rgba(0, 0, 0, 0.4)', true);
|
||||
}}>
|
||||
<View style={styles.button}>
|
||||
<Text>setTranslucent(true) and setBackgroundColor('rgba(0, 0, 0, 0.4)', true)</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
<TouchableHighlight
|
||||
style={styles.wrapper}
|
||||
onPress={() => {
|
||||
StatusBar.setTranslucent(false);
|
||||
StatusBar.setBackgroundColor('black', true);
|
||||
}}>
|
||||
<View style={styles.button}>
|
||||
<Text>setTranslucent(false) and setBackgroundColor('black', true)</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
const examples = [{
|
||||
title: 'StatusBar hidden',
|
||||
render() {
|
||||
return <StatusBarHiddenExample />;
|
||||
},
|
||||
}, {
|
||||
title: 'StatusBar style',
|
||||
render() {
|
||||
return <StatusBarStyleExample />;
|
||||
},
|
||||
platform: 'ios',
|
||||
}, {
|
||||
title: 'StatusBar network activity indicator',
|
||||
render() {
|
||||
return <StatusBarNetworkActivityExample />;
|
||||
},
|
||||
platform: 'ios',
|
||||
}, {
|
||||
title: 'StatusBar background color',
|
||||
render() {
|
||||
return <StatusBarBackgroundColorExample />;
|
||||
},
|
||||
platform: 'android',
|
||||
}, {
|
||||
title: 'StatusBar background color',
|
||||
render() {
|
||||
return <StatusBarTranslucentExample />;
|
||||
},
|
||||
platform: 'android',
|
||||
}, {
|
||||
title: 'StatusBar static API',
|
||||
render() {
|
||||
return <StatusBarStaticExample />;
|
||||
return <StatusBarStaticIOSExample />;
|
||||
},
|
||||
platform: 'ios',
|
||||
}, {
|
||||
title: 'StatusBar static API',
|
||||
render() {
|
||||
return <StatusBarStaticAndroidExample />;
|
||||
},
|
||||
platform: 'android',
|
||||
}, {
|
||||
title: 'StatusBar dimensions',
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<Text>Height: {StatusBar.currentHeight} pts</Text>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
platform: 'android',
|
||||
}];
|
||||
|
||||
exports.examples = examples;
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
wrapper: {
|
||||
borderRadius: 5,
|
||||
|
@ -39,8 +39,37 @@ type DefaultProps = {
|
||||
*/
|
||||
function mergePropsStack(propsStack: Array<Object>, defaultValues: Object): Object {
|
||||
return propsStack.reduce((prev, cur) => {
|
||||
return Object.assign(prev, cur);
|
||||
}, defaultValues);
|
||||
for (let prop in cur) {
|
||||
if (cur[prop] != null) {
|
||||
prev[prop] = cur[prop];
|
||||
}
|
||||
}
|
||||
return prev;
|
||||
}, Object.assign({}, defaultValues));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object to insert in the props stack from the props
|
||||
* and the transition/animation info.
|
||||
*/
|
||||
function createStackEntry(props: any): any {
|
||||
return {
|
||||
backgroundColor: props.backgroundColor != null ? {
|
||||
value: props.backgroundColor,
|
||||
animated: props.animated,
|
||||
} : null,
|
||||
barStyle: props.barStyle != null ? {
|
||||
value: props.barStyle,
|
||||
animated: props.animated,
|
||||
} : null,
|
||||
translucent: props.translucent,
|
||||
hidden: props.hidden != null ? {
|
||||
value: props.hidden,
|
||||
animated: props.animated,
|
||||
transition: props.showHideTransition,
|
||||
} : null,
|
||||
networkActivityIndicatorVisible: props.networkActivityIndicatorVisible,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@ -81,19 +110,34 @@ function mergePropsStack(propsStack: Array<Object>, defaultValues: Object): Obje
|
||||
const StatusBar = React.createClass({
|
||||
statics: {
|
||||
_propsStack: [],
|
||||
_defaultProps: {
|
||||
_defaultProps: createStackEntry({
|
||||
animated: false,
|
||||
showHideTransition: 'fade',
|
||||
backgroundColor: 'black',
|
||||
barStyle: 'default',
|
||||
translucent: false,
|
||||
hidden: false,
|
||||
networkActivityIndicatorVisible: false,
|
||||
},
|
||||
}),
|
||||
// Timer for updating the native module values at the end of the frame.
|
||||
_updateImmediate: null,
|
||||
// The current merged values from the props stack.
|
||||
_currentValues: null,
|
||||
|
||||
// TODO(janic): Provide a real API to deal with status bar height. See the
|
||||
// discussion in #6195.
|
||||
/**
|
||||
* The current height of the status bar on the device.
|
||||
*
|
||||
* @platform android
|
||||
*/
|
||||
currentHeight: StatusBarManager.HEIGHT,
|
||||
|
||||
// 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;
|
||||
StatusBar._defaultProps.hidden.value = hidden;
|
||||
if (Platform.OS === 'ios') {
|
||||
StatusBarManager.setHidden(hidden, animation);
|
||||
} else if (Platform.OS === 'android') {
|
||||
@ -107,7 +151,7 @@ const StatusBar = React.createClass({
|
||||
return;
|
||||
}
|
||||
animated = animated || false;
|
||||
StatusBar._defaultProps.barStyle = style;
|
||||
StatusBar._defaultProps.barStyle.value = style;
|
||||
StatusBarManager.setStyle(style, animated);
|
||||
},
|
||||
|
||||
@ -126,7 +170,7 @@ const StatusBar = React.createClass({
|
||||
return;
|
||||
}
|
||||
animated = animated || false;
|
||||
StatusBar._defaultProps.backgroundColor = color;
|
||||
StatusBar._defaultProps.backgroundColor.value = color;
|
||||
StatusBarManager.setColor(processColor(color), animated);
|
||||
},
|
||||
|
||||
@ -197,27 +241,31 @@ const StatusBar = React.createClass({
|
||||
};
|
||||
},
|
||||
|
||||
_stackEntry: null,
|
||||
|
||||
componentDidMount() {
|
||||
// Every time a StatusBar component is mounted, we push it's prop to a stack
|
||||
// and always update the native status bar with the props from the top of then
|
||||
// stack. This allows having multiple StatusBar components and the one that is
|
||||
// added last or is deeper in the view hierachy will have priority.
|
||||
StatusBar._propsStack.push(this.props);
|
||||
this._stackEntry = createStackEntry(this.props);
|
||||
StatusBar._propsStack.push(this._stackEntry);
|
||||
this._updatePropsStack();
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
// When a StatusBar is unmounted, remove itself from the stack and update
|
||||
// the native bar with the next props.
|
||||
const index = StatusBar._propsStack.indexOf(this.props);
|
||||
const index = StatusBar._propsStack.indexOf(this._stackEntry);
|
||||
StatusBar._propsStack.splice(index, 1);
|
||||
|
||||
this._updatePropsStack();
|
||||
},
|
||||
|
||||
componentDidUpdate(oldProps: Object) {
|
||||
const index = StatusBar._propsStack.indexOf(oldProps);
|
||||
StatusBar._propsStack[index] = this.props;
|
||||
componentDidUpdate() {
|
||||
const index = StatusBar._propsStack.indexOf(this._stackEntry);
|
||||
this._stackEntry = createStackEntry(this.props);
|
||||
StatusBar._propsStack[index] = this._stackEntry;
|
||||
|
||||
this._updatePropsStack();
|
||||
},
|
||||
@ -226,34 +274,51 @@ const StatusBar = React.createClass({
|
||||
* Updates the native status bar with the props from the stack.
|
||||
*/
|
||||
_updatePropsStack() {
|
||||
// Send the update to the native module only once at the end of the frame.
|
||||
clearImmediate(StatusBar._updateImmediate);
|
||||
StatusBar._updateImmediate = setImmediate(() => {
|
||||
const oldProps = StatusBar._currentValues;
|
||||
const mergedProps = mergePropsStack(StatusBar._propsStack, StatusBar._defaultProps);
|
||||
|
||||
// Update the props that have changed using the merged values from the props stack.
|
||||
if (Platform.OS === 'ios') {
|
||||
if (mergedProps.barStyle !== undefined) {
|
||||
StatusBarManager.setStyle(mergedProps.barStyle, this.props.animated);
|
||||
}
|
||||
if (mergedProps.hidden !== undefined) {
|
||||
StatusBarManager.setHidden(
|
||||
mergedProps.hidden,
|
||||
this.props.animated ? this.props.showHideTransition : 'none'
|
||||
if (!oldProps || oldProps.barStyle.value !== mergedProps.barStyle.value) {
|
||||
StatusBarManager.setStyle(
|
||||
mergedProps.barStyle.value,
|
||||
mergedProps.barStyle.animated,
|
||||
);
|
||||
}
|
||||
if (mergedProps.networkActivityIndicatorVisible !== undefined) {
|
||||
if (!oldProps || oldProps.hidden.value !== mergedProps.hidden.value) {
|
||||
StatusBarManager.setHidden(
|
||||
mergedProps.hidden.value,
|
||||
mergedProps.hidden.animated ?
|
||||
mergedProps.hidden.transition :
|
||||
'none',
|
||||
);
|
||||
}
|
||||
|
||||
if (!oldProps || oldProps.networkActivityIndicatorVisible !== mergedProps.networkActivityIndicatorVisible) {
|
||||
StatusBarManager.setNetworkActivityIndicatorVisible(
|
||||
mergedProps.networkActivityIndicatorVisible
|
||||
);
|
||||
}
|
||||
} else if (Platform.OS === 'android') {
|
||||
if (mergedProps.backgroundColor !== undefined) {
|
||||
StatusBarManager.setColor(processColor(mergedProps.backgroundColor), this.props.animated);
|
||||
if (!oldProps || oldProps.backgroundColor.value !== mergedProps.backgroundColor.value) {
|
||||
StatusBarManager.setColor(
|
||||
processColor(mergedProps.backgroundColor.value),
|
||||
mergedProps.backgroundColor.animated,
|
||||
);
|
||||
}
|
||||
if (mergedProps.hidden !== undefined) {
|
||||
StatusBarManager.setHidden(mergedProps.hidden);
|
||||
if (!oldProps || oldProps.hidden.value !== mergedProps.hidden.value) {
|
||||
StatusBarManager.setHidden(mergedProps.hidden.value);
|
||||
}
|
||||
if (mergedProps.translucent !== undefined) {
|
||||
if (!oldProps || oldProps.translucent !== mergedProps.translucent) {
|
||||
StatusBarManager.setTranslucent(mergedProps.translucent);
|
||||
}
|
||||
}
|
||||
// Update the current prop values.
|
||||
StatusBar._currentValues = mergedProps;
|
||||
});
|
||||
},
|
||||
|
||||
render(): ?ReactElement {
|
||||
|
@ -6,6 +6,7 @@ android_library(
|
||||
deps = [
|
||||
react_native_target('java/com/facebook/react/bridge:bridge'),
|
||||
react_native_target('java/com/facebook/react/common:common'),
|
||||
react_native_target('java/com/facebook/react/uimanager:uimanager'),
|
||||
react_native_dep('third-party/android/support/v4:lib-support-v4'),
|
||||
react_native_dep('third-party/java/infer-annotations:infer-annotations'),
|
||||
react_native_dep('third-party/java/jsr-305:jsr-305'),
|
||||
|
@ -7,30 +7,41 @@
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
|
||||
package com.facebook.react.modules.statusbar;
|
||||
|
||||
import android.animation.ArgbEvaluator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.support.v4.view.ViewCompat;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.facebook.react.bridge.Promise;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.UiThreadUtil;
|
||||
import com.facebook.react.common.MapBuilder;
|
||||
import com.facebook.react.uimanager.PixelUtil;
|
||||
|
||||
/**
|
||||
* {@link NativeModule} that allows changing the appearance of the status bar.
|
||||
*/
|
||||
public class StatusBarModule extends ReactContextBaseJavaModule {
|
||||
|
||||
private static final String ERROR_NO_ACTIVITY = "E_NO_ACTIVITY";
|
||||
private static final String ERROR_NO_ACTIVITY_MESSAGE =
|
||||
"Tried to change the status bar while not attached to an Activity";
|
||||
|
||||
private static final String HEIGHT_KEY = "HEIGHT";
|
||||
|
||||
public StatusBarModule(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
}
|
||||
@ -40,6 +51,19 @@ public class StatusBarModule extends ReactContextBaseJavaModule {
|
||||
return "StatusBarManager";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Map<String, Object> getConstants() {
|
||||
final Context context = getReactApplicationContext();
|
||||
final int heightResId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
|
||||
final float height = heightResId > 0 ?
|
||||
PixelUtil.toDIPFromPixel(context.getResources().getDimensionPixelSize(heightResId)) :
|
||||
0;
|
||||
|
||||
return MapBuilder.<String, Object>of(
|
||||
HEIGHT_KEY, height
|
||||
);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void setColor(final int color, final boolean animated, final Promise res) {
|
||||
final Activity activity = getCurrentActivity();
|
||||
|
Loading…
x
Reference in New Issue
Block a user