-
Notifications
You must be signed in to change notification settings - Fork 297
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
Best way to document a stable multi-dropdown nested view overlap / zindex solution? #376
Comments
I'm nearly complete with the screen that prompted this deep-dive, and I noticed that even the above solution is not quite enough to be cross-platform. It certainly fixes the common issue on iOS caused by the dropdown in non-sibling views having unexpected overlap behavior. However! If you apply the parent-container zIndex, then Android dropdowns are no longer touchable (as noted in other issues). But Android will continue to work correctly with the Dropdown zIndex/zIndexInverse props so long as the parent view container has no zIndex property at all. So the complete, works on both platform solutions actually has zIndex/zIndexInverse as documented in the multiple dropdown guide here, but also has a parent View zIndex prop included dynamically, like this chunk of layout: <View
style={[{
flexDirection: 'row',
justifyContent: 'space-evenly',},
(Platform.OS === 'ios' ? {zIndex: areaOpen ? 1 : 0} : {})]
}>
<View style={{justifyContent: 'center', alignContent: 'flex-end'}}>
<FontAwesome
name="puzzle-piece"
size={30}
color={styles.blue.color}
/>
</View>
<View style={styles.filterTextViewStyle}>
<Text style={{textAlign: 'left'}}>Área laboral:</Text>
</View>
<View style={{justifyContent: 'center'}}>
<DropDownPicker
open={areaOpen}
value={areaValue}
items={areaItems}
setOpen={setAreaOpen}
setValue={setAreaValue}
setItems={setAreaItems}
listMode="SCROLLVIEW"
style={styles.dropDownStyle}
zIndexInverse={7000}
zIndex={1000}
// containerStyle={{borderColor: 'green', borderWidth: 1}}
dropDownContainerStyle={{width: 200, backgroundColor: 'white'}}
listItemContainerStyle={{
width: 200,
// borderColor: 'red',
// borderWidth: 1,
}}
/>
</View>
</View> |
This has been user tested on real devices android + ios, plus android emulator / iOS simulator on current stable versions of everything and looks quite nice (nested View styling...) plus works everywhere FYI. Please note that I am not handling the "multiple dropdowns open at once" issue in my code above, which is an error. But this is focused on the zIndex / overlap issue |
No idea who is reading any of this but this library is solid. It deserves more community helping. So, here's the close function for multi-dropdowns, just call this as the Note that these are all my open dropdown state / state-toggle names. Yours will differ, but the pattern is super simple. Tested --> working, onOpen is apparently called before setXXXOpen() so there is not a race condition in my testing. const closeAllOpen = () => {
fechaOpen && setFechaOpen(false);
provinciaOpen && setProvinciaOpen(false);
nivelOpen && setNivelOpen(false);
discapacidadOpen && setDiscapacidadOpen(false);
salarioOpen && setSalarioOpen(false);
tipoOpen && setTipoOpen(false);
areaOpen && setAreaOpen(false);
return true;
}; |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Okay - for anyone else following along - I'm a collaborator on this repo (and the docs repo) now, and I usually rotate through the list of repositories I work on one a time, doing bursts of work each time I pass through, then letting them sit. After documenting the solution above here ☝️ I consider it already sort of "available for use / help" for anyone, so it's not super-urgent to make it in the official docs and it took some time to work out, so I'll let it sit, but I should be back through here in a little while with a real PR with it as an example If anyone else wants to take the above and clean it up before I get to it, that would be great though of course :-) |
When the Picker is wrapped in Animated component, it seems it ignores zIndexes on android :( |
@TomasSestak interesting! One of the things I found while developing the solution above was that "layout only" Views were collapsed as they went from JS to Native components on Android as an optimization. That's the underlying reason why the zIndex is conditional on platform in my solution above. zIndex will only be applied in react-native (or CSS on the web!) in peer elements in the same View container. There is no zIndex relationship between elements that have different View parents. That is a fundamental understanding you must have to make zIndex tricks work. But - on react-native android, layout-only Views are collapsed (and thus do not exist) at the native level so there is a little bit of wiggle room / difficult to understand but maybe useful behavior on android to set zIndexes that do actually relate to each other even if they are in different react view hierarchies. Given that as a basic understanding you might try re-organizing your views, or doing it in a more iOS-way (as above) if you need to wrap your dropdowns in other components. |
Hey, just replying to this with something that might be useful for android users using FlatList. Pseudo code: import { Platform } from "react-native";
import DropDownPicker from "react-native-dropdown-picker";
class Example extends Component {
state = {
activeDropdown: "",
fields: [
{ key: "1", label: "test", options: ["A", "B", "C"] },
{ key: "2", label: "other field", options: ["D", "E", "F"] },
],
};
render() {
return (
<>
<FlatList
data={this.state.fields}
extraData={this.state}
CellRendererComponent={({ children, index, style, ...props }) => {
const cellStyle = [
style,
Platform.OS === "android"
? { elevation: this.state.fields.length - index }
: { zIndex: this.state.fields.length - index },
];
return (
<View style={cellStyle} index={index} {...props}>
{children}
</View>
);
}}
renderItem={(item, index) => {
return (
<View
style={
this.state.activeDropdown === item.key
? Platform.OS === "android"
? { elevation: 10 }
: { zIndex: 10 }
: {}
}
>
<DropDownPicker
data={item.options}
open={this.state.activeDropdown === item.key}
onOpen={() => {
this.setState({ activeDropdown: item.key });
}}
onClose={() => {
this.setState({ activeDropdown: "" });
}}
handleChange={(value) => {
if (this.state.activeDropdown === item.key) {
// handle change here
}
}}
placeholder={item.label}
/>
</View>
);
}}
/>
</>
);
}
} I can always make a expo snack if requested. |
Oh that's a really nice piece of information - I honestly was not even aware of elevation existing I have the ability to merge PRs and such now to really elaborate on this case (stated generally: one or more pickers being occluded by other elements when opened) and since it is by far the most common difficulty in using the library I would love to have a concrete example like a snack if you could generate one 🙏 |
@hossein-zare @mikehardy |
@Mali-ai Create a new issue. We don't discuss personal issues in this thread. |
To make it work, I should increase the parent height |
adding zIndex and zIndexInverse property to DropDownPicker doesn't help me in android |
@mikehardy's solution didn't work for me on android. When I tried to select something, it instead opened the picker underneath the one that was open. I figured out that you can dynamically expand the padding and then set a negative margin of the parent view that contains the dropdown, and that solves the issue.
|
I have a dynamic form with multiple consecutive form element views, many of which contain dropdowns. I have it working like a charm in iOS by managing the dropdown open/closed states centrally and setting parent style zIndex values according to which dropdown is open. But I cannot seem to make the dropdown items clickable in Android when they hang outside of the dropdown's parent view, no matter what combination of incantations I try. Oddly I have found that, at least cosmetically, I need the zIndex even for Android. I'm not sure if it's because I'm using an old version of React Native (0.63.4) or perhaps related to the Android version I'm running in the emulator (API 30). For now my workaround is to use listMode MODAL on Android, but it would be really nice to get this figured out. I tried various combinations of zIndex, elevation, and the zIndex/zIndexInverse props to no avail. (To be honest, I don't even know what the zIndexInverse is supposed to mean, nor how those props are actually meant to work. The documentation is sparse, and I haven't dug into the library's code.) I am using the "against the rules" backgroundColor for the parent elements, which is important to our UI styling, but even removing that did not seem to change anything about my tests. (Based on what was said above in this thread, it seems perhaps that the backgroundColor simply affects the collapsibility of the parent view.) This is perhaps not even the right thread to share this in, as it is not specifically related to overlapping views. I cannot click anywhere in the dropdown where it overflows its parent view, regardless of whether anything else is overlapping it. But this does seem to be the most thorough discussion of these issues, so here I am. |
The zIndex and zIndexInverse is - if I remember correctly - used for when the dropdown is hanging down or when it goes up if I recall correctly? I strongly recommend going spelunking in the code to check things, it's not too bad to read through. Other than that I have to apologize: it appears you've gone past where I was with regard to both problems and attempts so I do not have specific guidance, other than to double and triple check "The Rules" and make sure you are not violating them: https://hossein-zare.github.io/react-native-dropdown-picker-website/docs/rules |
solution so far i had is setting
|
Always works for me const MyDropdownInputContainer = ({
open,
children,
}: ViewProps & { open?: boolean }) => (
<View style={{ ...(open && { zIndex: 1 }) }}>{children}</View>
); <MyDropdownInputContainer isOpen={someDropdownOpen}>
<DropDownPicker
...
open={someDropdownOpen}
setOpen={setSomeDropdownOpen}
zIndex={someDropdownOpen ? 1 : 0}
zIndexInverse={someDropdownOpen ? 1 : 0}
/>
</MyDropdownInputContainer>
|
If there is a solution we can agree upon I think this deserves to be promoted to the docs as this is inevitably going to keep on coming up in the issues |
Thanks, this is the only way I could get it to work! |
In my case, what worked was just adding a dynamic zIndex to the CellRendererComponent by using the index value from the props. Rest at other places, I didn't have to wrap the DropDownPicker component in a View, and neither did I have to use a zIndex prop for the DropDownPicker component. I tried all the issue threads in this repo that contained the zIndex or Flatlist keyword. In my case, I am using SectionList with the following prop, that's all, no other change was needed for me.
Update: Also, I just have single dropdown, so not sure in case of multiple dropdowns what other settings would go in place. |
Hi there 👋
This library is great, but it suffers from zIndexing / overlap issues that are basically out of it's control. There are issues related to it many times in the repo, I imagine it's a real bummer to deal with because it's just the way react-native lays out view elements.
But I think there's a solution that is really more about documentation than a technical fix.
Background, confirmed via testing on react-native 0.64.2 on real iOS device, iOS simulator and Android emuator
So what to do?
The solution I just tested, and it seems to work on both platforms is this:
stop using zIndex/zIndexInverse (it won't work on iOS and only works because of the "collapsable" memory optimization on Android) and instead set a zIndex prop on the parent Views dynamically, based on open state of the dropdown. If it's open, set zIndex to 1, if it is not open, set it to 0. Works?[edit: see below comment - on iOS zIndex/zIndexInverse does no harm, it is required and works on Android, and parent-view zIndex is required on iOS but breaks Android, so it requires a platform-specific include of parent-view zIndex]Here's an App.js that should show it working even with some dropdowns going up and some going down.
I think the best way to show this would be an entire page explaining it, with examples of the dead-end solutions (maybe?) plus this one to demonstrate why things work depending on the situation. It may involve a change to the "multiple dropdown" page or replace it?
I'd be happy to try a more formal writeup but first I thought I'd just propose it as a thought to see what you think.
Thanks!
The text was updated successfully, but these errors were encountered: