I have an App with two Views, blue view must be shown only when app is in active state (foreground) and the green view must be shown when app is put on background (e.g. clocking on hardware square button on Android).
The following picture shows what I currently get when I put the App in background state:
The following one is what I want to do when App is put on background (on iOS works, on Android not so well):
And this is the implementation.
Please, ignore for the moment that the component for iOS is almost identical to that for Android except for the style of the View. I was doing other tests with different components and for the moment it's okay for me to keep them like this. The difference between the two components (iOS / Android) lies in the style, because in iOS the zIndex
works, while in Android I have to use elevation
to overlap the views.
const showSecurityScreenFromAppState = appState =>
['background', 'inactive'].includes(appState);
const withSecurityScreenIOS = Wrapped => {
return class WithSecurityScreen extends React.Component {
constructor(props) {
super(props);
}
state = {
showSecurityScreen: showSecurityScreenFromAppState(AppState.currentState),
};
componentDidMount() {
AppState.addEventListener('change', this.onChangeAppState);
}
componentWillUnmount() {
AppState.removeEventListener('change', this.onChangeAppState);
}
onChangeAppState = nextAppState => {
const showSecurityScreen = showSecurityScreenFromAppState(nextAppState);
this.setState({showSecurityScreen});
};
//this.state.showSecurityScreen
render() {
return (
<>
<View style={[styles.container, {zIndex: this.state.showSecurityScreen ? 1 : -1}]}>
<View style={{flex: 1, backgroundColor: globalStyles.colors.customerGreen}}>
<View style={styles.upperView}>
<Text style={styles.upperViewText}>MyApp</Text>
</View>
</View>
</View>
<Wrapped {...this.props}/>
</>
);
}
};
};
const withSecurityScreenAndroid = Wrapped => {
return class WithSecurityScreen extends React.Component {
constructor(props) {
super(props);
}
state = {
showSecurityScreen: showSecurityScreenFromAppState(AppState.currentState),
};
componentDidMount() {
AppState.addEventListener('change', this.onChangeAppState);
}
componentWillUnmount() {
AppState.removeEventListener('change', this.onChangeAppState);
}
onChangeAppState = nextAppState => {
const showSecurityScreen = showSecurityScreenFromAppState(nextAppState);
this.setState({showSecurityScreen});
};
//this.state.showSecurityScreen
render() {
return (
<>
<View style={[styles.container, {elevation: this.state.showSecurityScreen ? 1 : -1}]}>
<View style={{flex: 1, backgroundColor: globalStyles.colors.customerGreen}}>
<View style={styles.upperView}>
<Text style={styles.upperViewText}>MyApp</Text>
</View>
</View>
</View>
<Wrapped {...this.props}/>
</>
);
}
};
};
export const withSecurityScreen =
Platform.OS === 'ios' ? withSecurityScreenIOS : withSecurityScreenAndroid;
There is not problems in the code, it works very well in iOS, but on Android sometimes it works and sometimes it doesn't. I suspect the cause is that Android OS, when the square button is pressed, it takes a screenshot of the current view and uses it as a background image of the App. Sometimes, however, it happens that the change of layer (elevation) is faster than the Android screenshot and therefore I can see the green screen in the background, as Android is using it as an image.
Is there a way to synchronize these operations? That is: can I make sure that when I press the square button, Android waits for the view to change and then let it go in the background?
Note: I have tested the functioning of elevation when the app is in the foreground, simply inverting the values of elevation
when it is in the background or in the foreground, I assure that elevation
is working.
Note: in the following animation, when the View in background tasks is white, is a fail. When the View becomes green in background, is a success. Why is random?
I realize now that the question may be badly set.
First of all I used incorrect terms to refer to the background status of the apps, the view I speak of in Android is called Recent Apps (or Task View). Then, secondly, in Recent Apps (Task View) what Android does, after pressing the square or circle button, a screenshot of the current view and then shows the Tasks View, using as the image for my App, the screenshot that he just did. The problem is quite annoying, because (as shown in the GIF above) sometimes the screenshot is done AFTER the change of view. Sometimes instead (and often times) the screenshot occurs BEFORE the change of view (the green one).
This is why sometimes in Task View I see the blue screen and sometimes the green one. It's almost a competition problem, let's say. My approach is probably not suitable, I should find another one. Is it possible to manually change the image used in Task View for my App?
You can try like this:
onChangeAppState = async nextAppState => {
const showSecurityScreen = await showSecurityScreenFromAppState(nextAppState);
this.setState({showSecurityScreen});
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With