flutterdropdownoverlay

I'm trying to create my own DropDownSearch widget in flutter but cannot set width for the CompositedTransformFollower


// thêm mới drop tự làm
class MyDropDown extends StatefulWidget {
  final List<DanhMucDoiTuongModel> list;
  final String label;
  final TextEditingController controller;
  final String? initValue;
  final Function(String) callback;
  bool? searchName = true;
  double? heightDrop;
  MyDropDown(
      {super.key,
      required this.list,
      required this.label,
      required this.controller,
      required this.initValue,
      required this.callback,
      this.searchName,
      this.heightDrop});

  @override
  State<MyDropDown> createState() => _MyDropDownState();
}

class _MyDropDownState extends State<MyDropDown> {
  List<DanhMucDoiTuongModel> searchList = [];
  final LayerLink _layerLink = LayerLink();
  double? _buttonWidth;
  var overlayController = OverlayPortalController();
  var tempLabel = ""; // tên hiển thị khi chọn 1 item

  @override
  void initState() {
    searchList = widget.list;
    if (widget.initValue == null) {
      tempLabel = widget.label;
    } else {
      tempLabel = widget.list
          .firstWhere((element) => element.ID == widget.initValue)
          .Ten;
    }
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return CompositedTransformTarget(
      link: _layerLink,
      child: InkWell(
        onTap: () {
          toggleDrop();
        },
        child: OverlayPortal(
            controller: overlayController,
            overlayChildBuilder: (context) {
              log(_buttonWidth.toString());
              return CompositedTransformFollower(
                link: _layerLink,
                targetAnchor: Alignment.bottomLeft,
                child: LimitedBox(
                  maxWidth: _buttonWidth!,
                  maxHeight: widget.heightDrop ?? 200,
                  child: SingleChildScrollView(
                    child: Card(
                      elevation: 8,
                      color: Colors.white,
                      child: Padding(
                        padding: const EdgeInsets.symmetric(horizontal: 10),
                        child: Column(
                          mainAxisSize: MainAxisSize.min,
                          children: [
                            Padding(
                              padding: const EdgeInsets.only(top: 7),
                              child: SizedBox(
                                height: 40,
                                child: TextField(
                                  onChanged: (text) {
                                    if (text.isNotEmpty) {
                                      if (widget.searchName!) {
                                        setState(() {
                                          searchList = widget.list
                                              .where((e) => e.Ten.toUpperCase()
                                                  .contains(text.toUpperCase()))
                                              .toList();
                                        });
                                      } else {
                                        setState(() {
                                          searchList = widget.list
                                              .where((e) => e.Ma.toUpperCase()
                                                  .contains(text.toUpperCase()))
                                              .toList();
                                        });
                                      }
                                    } else {
                                      setState(() {
                                        searchList = widget.list;
                                      });
                                    }
                                  },
                                  controller: widget.controller,
                                  decoration: InputDecoration(
                                    labelText: "Tìm ...",
                                    contentPadding: const EdgeInsets.symmetric(
                                      horizontal: 10,
                                      vertical: 8,
                                    ),
                                    border: OutlineInputBorder(
                                      borderRadius: BorderRadius.circular(8),
                                    ),
                                  ),
                                ),
                              ),
                            ),
                            LimitedBox(
                              maxHeight: widget.heightDrop == null
                                  ? 150
                                  : (widget.heightDrop! - 50),
                              child: ListView.builder(
                                  shrinkWrap: true,
                                  itemCount: searchList.length,
                                  itemBuilder: (context, index) {
                                    var curItem = searchList[index];
                                    return InkWell(
                                      onTap: () {
                                        setState(() {
                                          widget.callback(curItem.ID);
                                          tempLabel = curItem.Ten;
                                          searchList = widget.list;
                                          toggleDrop();
                                          // _isOpen = false;
                                          // hideOverlay();
                                        });
                                      },
                                      child: MyItemDrop(curItem: curItem),
                                    );
                                  }),
                            )
                          ],
                        ),
                      ),
                    ),
                  ),
                ),
              );
            },
            child: MyButtonDrop(label: tempLabel, onTap: toggleDrop)),
      ),
    );
  }

  toggleDrop() {
    _buttonWidth = context.size?.width;
    overlayController.toggle();
  }
}

class MyButtonDrop extends StatelessWidget {
  final String label;
  final Function() onTap;
  const MyButtonDrop({super.key, required this.label, required this.onTap});

  @override
  Widget build(BuildContext context) {
    return InkWell(
      onTap: onTap,
      child: Container(
        height: 50,
        decoration: BoxDecoration(
            border: Border.all(), borderRadius: BorderRadius.circular(10)),
        child: Row(
          children: [Text(label), const Icon(Icons.arrow_drop_down)],
        ),
      ),
    );
  }
}

class MyItemDrop extends StatelessWidget {
  final DanhMucDoiTuongModel curItem;
  const MyItemDrop({super.key, required this.curItem});

  @override
  Widget build(BuildContext context) {
    return Card(
      child: SizedBox(
        height: 40,
        child: Padding(
          padding: const EdgeInsets.only(left: 10, top: 10),
          child: Text(curItem.Ten),
        ),
      ),
    );
  }
}

I look at this post to do it https://medium.com/snapp-x/creating-custom-dropdowns-with-overlayportal-in-flutter-4f09b217cfce Still dont know why it not receive my value pass to? How can I do this ? Already take button in overlay and I call this widget in a AlertDialog Try search on youtube but nothing work for me


Solution

  • LimitedBox limits its size only when it's unconstrained. You need to wrap your CompositedTransformFollower with UnconstrainedBox.