AhmedLSayed9 / dropdown_button2

Flutter's core Dropdown Button widget with steady dropdown menu and many other features.
https://pub.dev/packages/dropdown_button2
MIT License
264 stars 122 forks source link

On mobile once keyboard open it's pushing the dropdown to top #298

Open prasanmoonraft opened 2 months ago

prasanmoonraft commented 2 months ago

On mobile it's pushing the entire drop down to top once you tap on the search box, also it's has used to filter the data based on location

AhmedLSayed9 commented 2 months ago

Pushing the dropdown to top when keyboard open is desired. What's the issue exactly here?

prasanmoonraft commented 2 months ago

It should go with the component right not only dropdown also, if you see only half of the component is visible and not able to properly search also @AhmedLSayed9

AhmedLSayed9 commented 2 months ago

Can you show minimal sample that produces the issue?

prasanmoonraft commented 2 months ago

class CustomSearchDropDown extends StatefulWidget { final String hint; final bool enabled; final String? value; final double? menuMaxHeight; final List items; final void Function(String?)? onChanged;

const CustomSearchDropDown({ super.key, this.value, this.hint = "", this.onChanged, this.menuMaxHeight, required this.enabled, required this.items, });

@override State createState() => _CustomSearchDropDownState(); }

class _CustomSearchDropDownState extends State { String? selectedValue; TextEditingController textEditingController = TextEditingController();

@override Widget build(BuildContext context) { return DropdownButtonHideUnderline( child: DropdownButton2( isExpanded: true, hint: Text( widget.items[0].location, overflow: TextOverflow.ellipsis, style: Theme.of(context).textTheme.labelLargeTStar800, ), items: widget.items .map((item) => DropdownMenuItem( value: item, child: Text( item.location, overflow: TextOverflow.ellipsis, style: Theme.of(context).textTheme.labelLargeTStar800, ), )) .toList(), value: selectedValue != null ? widget.items.firstWhere((item) => item.id == selectedValue) : null, onChanged: (value) { setState(() { selectedValue = value?.id; widget.enabled ? widget.onChanged!(value?.id) : null; }); }, buttonStyleData: ButtonStyleData( width: 175.0.w, padding: EdgeInsets.only(right: 8.0.s), decoration: BoxDecoration( border: Border.all(color: AppColors.white), color: AppColors.white, ), ), iconStyleData: IconStyleData( icon: SvgAssetWidget( image: SvgImages.downArrowIcon, height: 16.0.w, width: 16.0.w, ), ), dropdownStyleData: DropdownStyleData( width: 175.0.w, decoration: BoxDecoration( color: AppColors.white, border: Border.all(color: Colors.transparent), ), maxHeight: widget.menuMaxHeight, ), menuItemStyleData: MenuItemStyleData( height: 40.0.w, selectedMenuItemBuilder: (ctx, child) { return Container( color: AppColors.alto, child: child, ); }, ), dropdownSearchData: DropdownSearchData( searchController: textEditingController, searchInnerWidgetHeight: 38.0.w, searchInnerWidget: SizedBox( height: 38.0.w, child: TextFormField( expands: true, maxLines: null, style: Theme.of(context).textTheme.bodyLargeTStar, controller: textEditingController, decoration: InputDecoration( isDense: true, focusColor: AppColors.white, contentPadding: EdgeInsets.all(8.0.s), hintText: Strings.search, hintStyle: Theme.of(context).textTheme.bodyLargeTStarGray, ), ), ), searchMatchFn: (item, searchValue) { final location = item.value?.location ?? ''; final locationLower = location.toLowerCase(); final searchValueLower = searchValue.toLowerCase(); return locationLower.contains(searchValueLower); }, ), onMenuStateChange: (isOpen) { if (!isOpen) { textEditingController.clear(); } }, ), ); } } Container( height: isMobile ? null : 40.0.w, padding: EdgeInsets.only( right: 16.0.s, ), margin: const EdgeInsets.all(0), child: Row( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ SvgAssetWidget( image: SvgImages.importantContactIcon, width: 24.0.w, height: 24.0.h, ), SizedBox(width: 12.0.w), SizedBox( width: 100.0.w, child: Text( Strings.mySpoc.toUpperCase(), style: Theme.of(context).textTheme.headlineSmall, ), ), ], ), Container( width: 170.0.w, height: 25.0.s, color: AppColors.white, child: CustomSearchDropDown( hint: Strings.search, menuMaxHeight: 200.0.s, enabled: true, value: selectedValue, items: widget.dropdownItems, onChanged: (value) { setState(() { if (value != null) { selectedValue = value; widget.callback!(value); } }); }, ), ) ], ), );

AhmedLSayed9 commented 2 months ago

I need a minimal sample that I can run on my device. Can you try using the latest 3.0.0-beta.16 version?

AhmedLSayed9 commented 2 months ago

Test the following sample and try updating it to reproduce the issue:

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Test',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final List<String> items = [
    'A_Item1',
    'A_Item2',
    'A_Item3',
    'A_Item4',
    'B_Item1',
    'B_Item2',
    'B_Item3',
    'B_Item4',
  ];

  final valueListenable = ValueNotifier<String?>(null);
  final TextEditingController textEditingController = TextEditingController();

  @override
  void dispose() {
    textEditingController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        mainAxisAlignment: MainAxisAlignment.end,
        children: [
          Padding(
            padding: const EdgeInsets.only(bottom: 100),
            child: DropdownButtonHideUnderline(
              child: DropdownButton2<String>(
                isExpanded: true,
                hint: Text(
                  'Select Item',
                  style: TextStyle(
                    fontSize: 14,
                    color: Theme.of(context).hintColor,
                  ),
                ),
                items: items
                    .map((item) => DropdownItem(
                          value: item,
                          height: 40,
                          child: Text(
                            item,
                            style: const TextStyle(
                              fontSize: 14,
                            ),
                          ),
                        ))
                    .toList(),
                valueListenable: valueListenable,
                onChanged: (value) {
                  valueListenable.value = value;
                },
                buttonStyleData: const ButtonStyleData(
                  padding: EdgeInsets.symmetric(horizontal: 16),
                  height: 40,
                  width: 200,
                ),
                dropdownStyleData: const DropdownStyleData(
                  maxHeight: 200,
                ),
                dropdownSearchData: DropdownSearchData(
                  searchController: textEditingController,
                  searchBarWidgetHeight: 50,
                  searchBarWidget: Container(
                    height: 50,
                    padding: const EdgeInsets.only(
                      top: 8,
                      bottom: 4,
                      right: 8,
                      left: 8,
                    ),
                    child: TextFormField(
                      expands: true,
                      maxLines: null,
                      controller: textEditingController,
                      decoration: InputDecoration(
                        isDense: true,
                        contentPadding: const EdgeInsets.symmetric(
                          horizontal: 10,
                          vertical: 8,
                        ),
                        hintText: 'Search for an item...',
                        hintStyle: const TextStyle(fontSize: 12),
                        border: OutlineInputBorder(
                          borderRadius: BorderRadius.circular(8),
                        ),
                      ),
                    ),
                  ),
                  noResultsWidget: const Padding(
                    padding: EdgeInsets.all(8),
                    child: Text('No Item Found!'),
                  ),
                  searchMatchFn: (item, searchValue) {
                    return item.value.toString().contains(searchValue);
                  },
                ),
                //This to clear the search value when you close the menu
                onMenuStateChange: (isOpen) {
                  if (!isOpen) {
                    textEditingController.clear();
                  }
                },
              ),
            ),
          ),
        ],
      ),
    );
  }
}