0

when i open upper dropdown, when it goes over other dropdown menu it hides behind. I am Using a dropdown menu, this issue only arrises when i use two dropdown menu together in a column.

it only does this when page is scrolled a little, normally it behaves normally.

https://i.sstatic.net/mdfmEISD.jpg

    Widget myDropDown({
  required String title,
  required List<DropdownMenuEntry> entries,
  bool? hideTitle,
  bool? autoWidth,
  double? width,
  int? Function(List<DropdownMenuEntry<dynamic>>, String)? searchCallback,
  bool? requestFocus,
  TextEditingController? textController,
  void Function(dynamic)? onSelected,
  bool? enabled,
  dynamic initialSelection,
  FocusNode? focusNode,
  bool showHint = true,
  bool hasData = false,
  VoidCallback? hasDataOnTap,
}) {
  return Padding(
    padding: EdgeInsets.only(bottom: 12.0.h),
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        (hideTitle ?? false)
            ? const SizedBox()
            : Column(
                children: [
                  CustomText(
                    title: title,
                    fontSize: 14.sp,
                    bold: true,
                    color: AppColors.primaryColor,
                  ),
                  12.verticalSpace,
                ],
              ),
        DropdownMenu(
          key: UniqueKey(),
          initialSelection: initialSelection,
          enabled: enabled ?? true,
          enableSearch: false,
          focusNode: focusNode,
          onSelected: onSelected,
          requestFocusOnTap: requestFocus ?? false,
          controller: textController,
          menuHeight: Get.height * 0.5,
          searchCallback: searchCallback,
          expandedInsets: EdgeInsets.all(0.sp),
          hintText: showHint ? "Select" : null,
          menuStyle: MenuStyle(
            backgroundColor: WidgetStatePropertyAll(AppColors.white),
          ),
          trailingIcon: hasData
              ? InkWell(
                  onTap: hasDataOnTap,
                  child: Icon(Icons.close),
                )
              : const Icon(Icons.keyboard_arrow_down),
          selectedTrailingIcon: const Icon(Icons.keyboard_arrow_up),
          inputDecorationTheme: InputDecorationTheme(
            isDense: true,
            fillColor: AppColors.white,
            filled: true,
            contentPadding: EdgeInsets.symmetric(
              horizontal: 15.w,
            ),
            border: OutlineInputBorder(
              borderSide: const BorderSide(color: AppColors.iconGrey),
              borderRadius: BorderRadius.circular(8.sp),
            ),
          ),
          dropdownMenuEntries: entries,
        ),
      ],
    ),
  );
}

this is my widget that i am using while using two of these in a column it causes issues

5
  • can you share code.
    – Munsif Ali
    Commented Apr 15 at 6:22
  • Add some tried code. Commented Apr 15 at 6:23
  • Added my code to the post
    – parv
    Commented Apr 15 at 6:29
  • Are you trying to close first one if that is open? Commented Apr 15 at 10:32
  • no, the flow is like this at first i open dropdown, it works perfectly i scroll page a little, then when i open the dropdown, it behaves like this only happens when two dropdown menus are in single column
    – parv
    Commented Apr 15 at 10:41

1 Answer 1

0

The issue you're encountering—where the upper dropdown menu hides behind the lower dropdown when scrolled—occurs because of how Flutter handles stacking and clipping in a Column within a scrollable widget (e.g., SingleChildScrollView or ListView). By default, dropdown menus in Flutter's DropdownMenu are rendered in a separate overlay layer, but their positioning and stacking can be affected by the parent widget's clipping behavior or z-index when scrolling.

The problem is more pronounced when:

Two DropdownMenu widgets are placed in a Column. The parent widget is scrollable, causing the dropdown's overlay to be clipped or misaligned. The Stack order of the dropdowns is not properly managed, leading to one dropdown's overlay appearing behind another.

Solution

To fix this, you need to ensure that the dropdown menu's overlay is rendered above all other widgets and is not clipped by the scrollable parent. You can achieve this by:

Using ClipBehavior: Disable clipping in the parent scrollable widget (e.g., SingleChildScrollView) to allow the dropdown menu to overflow without being hidden. Adjusting MenuStyle: Explicitly set the elevation in the MenuStyle to ensure the dropdown menu has a higher z-index. Using Stack for Overlap Control: If the issue persists, wrap the dropdowns in a Stack to control their rendering order explicitly. Ensuring Unique Keys: Verify that each DropdownMenu has a unique key to avoid rendering conflicts.

Here’s an updated version of your myDropDown widget with fixes:

Widget myDropDown({
  required String title,
  required List<DropdownMenuEntry> entries,
  bool? hideTitle,
  bool? autoWidth,
  double? width,
  int? Function(List<DropdownMenuEntry<dynamic>>, String)? searchCallback,
  bool? requestFocus,
  TextEditingController? textController,
  void Function(dynamic)? onSelected,
  bool? enabled,
  dynamic initialSelection,
  FocusNode? focusNode,
  bool showHint = true,
  bool hasData = false,
  VoidCallback? hasDataOnTap,
}) {
  return Padding(
    padding: EdgeInsets.only(bottom: 12.0.h),
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        if (!(hideTitle ?? false)) ...[
          CustomText(
            title: title,
            fontSize: 14.sp,
            bold: true,
            color: AppColors.primaryColor,
          ),
          12.verticalSpace,
        ],
        DropdownMenu(
          key: UniqueKey(), // Ensure unique key for each dropdown
          initialSelection: initialSelection,
          enabled: enabled ?? true,
          enableSearch: false,
          focusNode: focusNode,
          onSelected: onSelected,
          requestFocusOnTap: requestFocus ?? false,
          controller: textController,
          menuHeight: Get.height * 0.5,
          searchCallback: searchCallback,
          expandedInsets: EdgeInsets.zero, // Simplified
          hintText: showHint ? "Select" : null,
          menuStyle: MenuStyle(
            backgroundColor: const WidgetStatePropertyAll(AppColors.white),
            elevation: const WidgetStatePropertyAll(8), // Higher z-index
            shape: WidgetStatePropertyAll(
              RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(8.sp),
              ),
            ),
          ),
          trailingIcon: hasData
              ? InkWell(
                  onTap: hasDataOnTap,
                  child: const Icon(Icons.close),
                )
              : const Icon(Icons.keyboard_arrow_down),
          selectedTrailingIcon: const Icon(Icons.keyboard_arrow_up),
          inputDecorationTheme: InputDecorationTheme(
            isDense: true,
            fillColor: AppColors.white,
            filled: true,
            contentPadding: EdgeInsets.symmetric(horizontal: 15.w),
            border: OutlineInputBorder(
              borderSide: const BorderSide(color: AppColors.iconGrey),
              borderRadius: BorderRadius.circular(8.sp),
            ),
          ),
          dropdownMenuEntries: entries,
        ),
      ],
    ),
  );
}

Example Usage in a Scrollable Column

To ensure the dropdowns work correctly when scrolled, wrap them in a SingleChildScrollView with clipBehavior set to Clip.none:

Widget build(BuildContext context) {
  return SingleChildScrollView(
    clipBehavior: Clip.none, // Prevent clipping of dropdown menus
    child: Column(
      children: [
        myDropDown(
          title: "First Dropdown",
          entries: [
            DropdownMenuEntry(value: "1", label: "Option 1"),
            DropdownMenuEntry(value: "2", label: "Option 2"),
          ],
        ),
        myDropDown(
          title: "Second Dropdown",
          entries: [
            DropdownMenuEntry(value: "3", label: "Option 3"),
            DropdownMenuEntry(value: "4", label: "Option 4"),
          ],
        ),
      ],
    ),
  );
}

Explanation of Fixes

ClipBehavior: Setting clipBehavior: Clip.none on the SingleChildScrollView ensures that the dropdown menu’s overlay is not clipped when it overflows the parent’s bounds. Elevation: Adding elevation: WidgetStatePropertyAll(8) in MenuStyle ensures the dropdown menu appears above other widgets in the stack. Unique Keys: Using UniqueKey() ensures each DropdownMenu is treated as a distinct widget, preventing rendering conflicts. Simplified Insets: Changed expandedInsets: EdgeInsets.all(0.sp) to EdgeInsets.zero for clarity and consistency.

Additional Suggestions

Test with Scrolling: Test the dropdowns in a scrollable context with various scroll positions to ensure the overlay behaves correctly.
Use a Stack if Needed: If the issue persists, consider wrapping the Column in a Stack and controlling the dropdowns’ z-index explicitly:
    Stack(
      children: [
        Positioned.fill(
          child: SingleChildScrollView(
            child: Column(
              children: [
                myDropDown(...),
                myDropDown(...),
              ],
            ),
          ),
        ),
      ],
    );
Check Parent Constraints: Ensure the parent widget (e.g., Scaffold or Container) does not impose tight constraints that affect the dropdown’s overlay positioning.
Debug Overlay: Use Flutter’s debugPaintLayerBordersEnabled = true in main.dart to visualize the dropdown’s overlay and identify clipping issues.

Why It Happens Only When Scrolled?

When the page is scrolled, the scrollable widget’s viewport changes, and Flutter may clip the dropdown’s overlay if it extends beyond the visible area. This is why disabling clipping and ensuring proper elevation resolves the issue.

This solution should prevent the upper dropdown from hiding behind the lower one, even when scrolled.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.