-
Notifications
You must be signed in to change notification settings - Fork 24.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
zIndex does not work with dynamic components on Android #8968
Comments
Still an issue in 0.32. |
any news? |
Same thing happened to me, so I'll throw in some more details: Here's the code for a component that does this sort of thing:
|
+1, happened to me in a similar situation. |
If it's helpful to anyone, I created a import React, { Component } from 'react';
import {
View,
StyleSheet,
Platform
} from 'react-native';
const hideable_styles = StyleSheet.create({
android_hidden: {
height: 0,
borderWidth: 0,
paddingTop: 0,
paddingBottom: 0,
marginTop: 0,
marginBottom: 0
}
});
class Hideable extends Component {
render(){
const {hide, children, style = {}, ...rest_props} = this.props;
// on ios, best way to hide is to return null
if (hide && Platform.OS === 'ios') return null;
// otherwise, if android, going to add in the special android hidden styles
const conditional_layout = hide ? hideable_styles.android_hidden : {};
const styles = [style, conditional_layout];
return (
<View {...rest_props} style={styles}>
{children}
</View>
);
}
}
export default Hideable; Here's a simple use: const simpleTestHideable = ({hide = true}) => {
return (
<Hideable hide={hide} style={{zIndex: 1, backgroundColor: 'red', height: 100}} >
<Text>{hide ? 'You should not see this' : 'You should see this' }</Text>
</Hideable>
);
} Here's a more complex, interactive usage example: class TestHideable extends Component {
constructor(props){
super(props);
this.state = { hide_content: false };
this.toggleContent = this.toggleContent.bind(this);
}
toggleContent(){
this.setState({hide_content: !this.state.hide_content});
}
render(){
const { hide_content } = this.state;
return (
<View style={{paddingTop: 20}}>
<Hideable
hide={hide_content}
anotherProp="foo"
style={{
padding: 10,
height: 100,
borderWidth: 0.5,
borderColor: '#d6d7da',
marginTop: 100,
marginBottom: 100,
backgroundColor: 'red',
zIndex: 2
}} >
<Text>I am showing!</Text>
</Hideable>
<Text onPress={this.toggleContent}>{hide_content ? 'SHOW!' : 'HIDE!'}</Text>
</View>
)
}
}
export default TestHideable; You should be able to pass through whatever styles or props you'd like to Also, @tioback, I noticed you set a negative I'm still pretty new to React Native so, grain of salt. |
@liamfd no, I don't recommend for, nor against it. Might be some left-over from a failed test. |
Hi, TL;DR; Details: Here is slightly modified example using three absolutely positioned elements, each subsequent of them have lower zIndex, so red is on top (60px height), green is underneath (90px height), and the blue is underneath (120px height). When the green is removed, the expected behaviour would be that green is completely removed from subviews, the remaining two elements would have their zIndex (order) recalculated, so we would see only red and blue underneath it. Modified example in the fresh react-native app 0.37.0: import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
export default class zindex extends Component {
constructor(props) {
super(props);
this.state = {
showGreen: true
};
}
render() {
return (
<View style={{flex: 1}}>
<View style={[styles.item, {zIndex: 3, backgroundColor: 'red'}]}>
<Text>zIndex: 3</Text>
</View>
{this.state.showGreen ?
<View style={[styles.item, {zIndex: 2, backgroundColor: 'green', height: 90}]}>
<Text>zIndex: 2</Text>
</View> : null
}
<View style={[styles.item, {zIndex: 1, backgroundColor: 'blue', height: 120}]}>
<Text>zIndex: 1</Text>
</View>
<View style={styles.button}>
<Text onPress={() => this.setState({ showGreen: !this.state.showGreen })}>
Toggle green
</Text>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
item: {
position: 'absolute',
left: 0,
right: 0,
top: 0,
height: 60
},
button: {
position: 'absolute',
left: 0,
right: 0,
backgroundColor: 'gray',
top: 150,
height: 30
}
});
AppRegistry.registerComponent('zindex', () => zindex); Not sure how I will proceed with this issue, but I will keep posting any ideas if I find them. Update 1: If I initially put the showGreen to false, then add it by toggling the button, everything is fine. I suspect that the views are reordered by zIndex only when they're added, but not when they're removed. Might it be related to this commit ? In the ViewGroupManager.java and ReactViewManager.java the reordering is not called on removeViewAt, might this be a problem? I'm not a Java expert though, would appreciate if someone could have a closer look at this particular case. |
Yo I'm the author of that commit :) @asgvard Thanks for the fantastic bug reporting. I think you're right, check out: react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewGroupManager.java Line 123 in 9ee815f
I think the fix is as simple as matching the public void removeViewAt(T parent, int index) {
parent.removeViewAt(index);
reorderChildrenByZIndex(parent)
} I don't really have the bandwidth to PR a fix and test it right now, but you probably could :) It's a good first PR. |
@tuckerconnelly Hey :) So today I made a try to fix this issue with simply adding the Here is my modified JS code: <View accessibilityLabel="RED" style={[styles.item, {zIndex: 3, backgroundColor: 'red'}]}>
<Text>zIndex: 3</Text>
</View>
{this.state.showGreen ?
<View accessibilityLabel="GREEN" style={[styles.item, {zIndex: 2, backgroundColor: 'green', height: 90}]}>
<Text>zIndex: 2</Text>
</View> : null
}
<View accessibilityLabel="BLUE" style={[styles.item, {zIndex: 1, backgroundColor: 'blue', height: 120}]}>
<Text>zIndex: 1</Text>
</View>
<View accessibilityLabel="BUTTON" style={styles.button}>
<Text onPress={() => this.setState({ showGreen: !this.state.showGreen })}>
Toggle green
</Text>
</View> The result leads me to even more deep problem. From JS prospective I'm removing Green view, but in Java it actually tries to remove Blue:
Seems that in Will post any updates. |
UPDATE: First of all, I found out that it has nothing to do with the reorderChildrenByZIndex() at all, because we actually don't need to reorder children after we remove something, because the relative zIndex order for remaining items remain the same. The problem was exactly in that it was removing the wrong Fixed by relying on Also this issue happens when Adding views, it adds them in the wrong index :) But since after adding the views we're doing reorder again, it doesn't matter that it was added into the wrong place. So the proposed solution is to change I will prepare PR soon :) |
@asgvard Legend! Thanks! |
Seems this PR brakes few unit tests (yes I should've double-checked that :) ), will investigate why it failed and prepare another one. |
Ok so seems initial idea of just using |
Any updates on this issue? |
Commit facebook@3d3b067 implemented zIndex support for Android. However after zIndex resorting of the views, the JS doesn't know about the new order. When dynamically removing the view from an array of views, JS sends the command to remove the view at certain index, which is not the same in Java since the order of items changed. Test Plan: Related issue and the simple empty react-native 0.37 app where it was tested: facebook#8968 In `manageChildren` in `NativeViewHierarchyManager.java` there was a loop by `indicesToRemove`, call `viewManager.removeViewAt(viewToManage, indexToRemove)`. However if the view is animated and it's ID in the array of `tagsToDelete`, do nothing and delegate this job of removing item to the loop by `tagsToDelete`. Now we propagate `tagsToRemove` instead from `UIImplementation` to `NativeViewHierarchyOptimized` to `NativeViewHierarchyManager` and using it instead of `indicesToRemove`. Also by having the old `indicesToRemove` loop we having the case that the *wrong* view is removed, but then, *correct* view is dropped in `tagsToDelete` loop. In result we have inconsistency when removing one view but dropping another. It's described in more details in mentioned above related issue comments.
Any updates on this issue? |
any updates? |
I'm experiencing this also, |
I'm still experiencing this just for the record! |
me to, any update? |
For anyone still stuck on the old RN here's a function I use that can be spread into your styles. It's based on the ideas presented by others above:
Use it like this in place of e.g:
Remove the Flow type checking from the function if you don't need it |
@glenn-axsy and others reading his comment, just a warning: |
Reviewed By: shergin Differential Revision: D5917111 fbshipit-source-id: e3d97f26b6aada199f700ec6659ace0d7dffd4c5
My RN version is 0.49.5 and I've encountered the same issue when setting the |
My react-native version is 0.49.3 and I am still encountering this problem with the zIndex and the elevation in android. I also used the @glenn-axsy workaround but still couldn't solve the issue. In the image below I want the user icon on top of the View but it is hiding and not coming on the top as expected |
Why this issue is closed? zIndex still not working on Android, and elevation is not the solution, because of mess of pointer-events. |
Issue exists with react-native version 0.50.3 |
still not working on Android :/ Invalid props.style key elevation supplied to Image. |
you can finish the work without zIndex |
It is still not working! this is a mess. I was using zindex but not using is not the solution |
+1. Works great on ios, breaks views in android |
@janicduplessis |
Issue exists with react-native version 0.51.0 too |
damm work great in IOS but in ANDROID crash , any update ? |
It's been unresolved for too long, any updates? |
0.51.0 |
0.52.1 |
still occur on [email protected] |
0.54.0 |
please check this newly opened issue. It has a repo that reproduces the problem. |
v0.54.2 Still a problem. |
Still having this issue with v0.55.2 |
still |
Can we just agree that this issue needs to be reopen NOW? |
Still exist in v0.55.4 |
Yep, having the same issue still. Even setting as absolute, the component will never render on top of the components, always will be hidden by the parent component. |
I am trying to render elements conditionally where each element has different zIndex style property.
Using folowing code in Android emulator with react-native 0.30.0.
Initial screen looks like expected:
When I click 'Toggle green' button to dynamically show/hide green element it hides blue element instead and furthermore element's text is missing:
When I click the button again, red and green elements remains visible and the toggle button jumps down.
The text was updated successfully, but these errors were encountered: