Flutter DropDownButton Popup 200px below Button

Sebastian Rüttger picture Sebastian Rüttger · Jan 13, 2020 · Viewed 9k times · Source

I'm using a DropDownButton with a custom style inside a ListView. My problem is: the PopupMenu opens about 200-300px below the Button so it looks like the Button below that has opened: enter image description here

I wrapped the Dropdown in a custom style, but i already tried removing that and that did nothing. I've also tried to use just a normal Dropdownbutton, but that had the same effect. the corresponding build:

    @override
Widget build(BuildContext context) {
    homeModel = Provider.of<HomeModel>(context);
    model = Provider.of<TransferModel>(context);
    navigator = Navigator.of(context);
    var items = model.items.entries.toList();
    return Container(
      color: Colors.white,
      child: ListView.builder(
        physics: BouncingScrollPhysics(),
        itemCount: model.items.entries.length,
        itemBuilder: (BuildContext context, int index) {
              return Padding(
                padding: const EdgeInsets.only(left: 30, right: 30, top: 10),
                child: CustomDropDown(
                  errorText: "",
                  hint: items[index].value["label"],
                  items: items[index]
                      .value["items"]
                      .asMap()
                      .map((int i, str) => MapEntry(
                          i,
                          DropdownMenuItem(
                            value: i,
                            child: Text(str is Map
                                ? str["displayName"].toString()
                                : str.toString()),
                          )))
                      .values
                      .toList()
                      .cast<DropdownMenuItem<int>>(),
                  value: items[index].value["selected"],
                  onChanged: (position) =>
                      model.selectItem(items[index].key, position),
                ),
              );
        },
      ),
    );

  }

CustomDropDown:

class CustomDropDown extends StatelessWidget {
  final int value;
  final String hint;
  final String errorText;
  final List<DropdownMenuItem> items;
  final Function onChanged;

  const CustomDropDown(
      {Key key,
      this.value,
      this.hint,
      this.items,
      this.onChanged,
      this.errorText})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        Container(
          decoration: BoxDecoration(
              color: Colors.grey[100], borderRadius: BorderRadius.circular(30)),
          child: Padding(
            padding:
                const EdgeInsets.only(left: 30, right: 30, top: 10, bottom: 5),
            child: DropdownButton<int>(
              value: value,
              hint: Text(
                hint,
                style: TextStyle(fontSize: 20),
                overflow: TextOverflow.ellipsis,
              ),
              style: Theme.of(context).textTheme.title,
              items: items,
              onChanged: (item) {
                onChanged(item);
              },
              isExpanded: true,
              underline: Container(),
              icon: Icon(Icons.keyboard_arrow_down),
            ),
          ),
        ),
        if (errorText != null) 
          Padding(
            padding: EdgeInsets.only(left: 30, top: 10),
            child: Text(errorText, style: TextStyle(fontSize: 12, color: Colors.red[800]),),
          )

      ],
    );
  }
}

edit: I've just noticed, that the popup always opens in the screen center. But I still have no idea why that is.

edit 2: thanks to @João Soares I've now narrowed down the issue: I surround the Widget with the ListView with an AnimatedContainer for opening and closing the menu. The padding of this container seems to be the culprit, but i have no idea how i can fix this, since i need that Container: (the Child is the ListView Widget)

  class ContentSheet extends StatelessWidget {
  final Widget child;
  final bool isMenuVisible;

  const ContentSheet({Key key, this.child, this.isMenuVisible}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: EdgeInsets.only(top: 50),
      child: AnimatedContainer(
        duration: Duration(milliseconds: 450),
        curve: Curves.elasticOut,
        padding: EdgeInsets.only(top: isMenuVisible ? 400 : 100),
        child: ClipRRect(
          borderRadius: BorderRadius.only(
              topLeft: Radius.circular(20), topRight: Radius.circular(20)),
          child: Container(
            decoration: BoxDecoration(
              borderRadius: BorderRadius.only(
                  topLeft: Radius.circular(20), topRight: Radius.circular(20)),
              color: Colors.white,
            ),
            child: child
          ),
        ),
      ),
    );
  }
}

Answer

Jo&#227;o Soares picture João Soares · Jan 13, 2020

I've tried your CustomDropDown widget with the code below and it works as expected, without the dropdown showing lower in the view. Something else in your code may be affecting its position.

class DropdownIssue extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _DropdownIssueState();
  }
}

class _DropdownIssueState extends State<DropdownIssue> {
  int currentValue = 0;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        color: Colors.grey,
        child: Container(
          alignment: Alignment.center,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              CustomDropDown(
                hint: 'hint',
                errorText: '',
                value: currentValue,
                items: [
                  DropdownMenuItem(
                    value: 0,
                    child: Text('test 0'),
                  ),
                  DropdownMenuItem(
                    value: 1,
                    child: Text('test 1'),
                  ),
                  DropdownMenuItem(
                    value: 2,
                    child: Text('test 2'),
                  ),
                ].cast<DropdownMenuItem<int>>(),
                onChanged: (value) {
                  setState(() {
                    currentValue = value;
                  });
                  print('changed to $value');
                }
              ),
            ],
          ),
        )
      ),
    );
  }
}