以编程方式打开Flutter下拉菜单

3

我正在尝试构建一个可搜索的下拉菜单,它将在每次按钮点击时从服务中加载值。因此,我已经把DropDownButton和TextField封装在Stack小部件中。

在键盘按下时,我们会从api获取响应,目前为止一切都很好。但是,在从api获取数据后,下拉菜单没有打开。通过深入挖掘,我知道必须手动点击才能打开它,但由于它在堆叠中,并且第二个孩子是TextField,所以我无法点击它。

但是编程方式打开DropDownButton按钮是不可能的。所以我尝试了stackoverflow上的这个答案 https://dev59.com/DFMH5IYBdhLWcg3w7Vzx#59499191 但它没有起作用。

以下是我的代码,没有来自stackoverflow的解决方案。

import 'package:flutter/material.dart';
import 'package:giphy/services/gifs_service.dart';
import 'package:giphy/shared/autocomplete.dart';

class TestDropDown extends StatefulWidget {
  // const TestDropDown({Key? key}) : super(key: key);
  @override
  _TestDropDownState createState() => _TestDropDownState();
}

class _TestDropDownState extends State<TestDropDown> {
  final GifyService _service = GifyService();

  final TextEditingController _gifSearchController = TextEditingController();

  List<SearchData> _dropDownResult = <SearchData>[];

  GlobalKey key = GlobalKey();

  // T? _findChildWidgetFromKey<T extends Widget>(
  //     BuildContext? context, T childWidget) {
  //   T? detector;
  //   context!.visitChildElements((element) {
  //     if (element.widget == childWidget) {
  //       detector = element.widget as T;
  //     }
  //   });

  //   return detector;
  // }

  Widget _buildDropDown(List<SearchData> searchData) => DropdownButton<String>(
        isExpanded: true,
        key: key,
        onChanged: (String? value) {},
        items: searchData
            .map(
              (e) => DropdownMenuItem<String>(
                child: Text(e.name ?? ''),
                value: e.name ?? '',
              ),
            )
            .toList(),
      );

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          _buildDropDown(_dropDownResult),
          Container(child: () {
            if (_dropDownResult.length > 0) {
              _buildDropDown(_dropDownResult);
            }
          }()),
          TextField(
            controller: _gifSearchController,
            decoration: InputDecoration(
              border: OutlineInputBorder(
                borderSide: BorderSide(width: 0.5),
                borderRadius: BorderRadius.circular(21),
              ),
            ),
            onChanged: (String value) async {
              AutoComplete result = await _service.getSearchKeywords(value);
              setState(() {
                _dropDownResult = result.data;
              });
            },
          ),
        ],
      ),
    );
  }
}
3个回答

1
如果你想自动完成文本框,那么你可以使用autocomplete_textfield包。
或者,如果你想自己构建它,那么你可以尝试使用容器代替下拉菜单的不同方法。

这些包能否在每次按键时从API加载数据? - Yaseen
是的,它提供了textChanged函数,您可以从API获取数据。 - hrushikesh kuklare

0

尝试了一些包后,我无法基于API调用进行Flutter自动完成。

因此决定尝试其他方法,并在Flutter中使用Overlay

import 'dart:async';

import 'package:flutter/material.dart';

class TestDropDown extends StatefulWidget {
  @override
  _TestDropDownState createState() => _TestDropDownState();
}

class _TestDropDownState extends State<TestDropDown> {
  late OverlayEntry _overlayEntry;
  Timer? _debounce;
  _showOverlay(BuildContext context) {
    OverlayState? state = Overlay.of(context);
    final RenderBox? box = key.currentContext!.findRenderObject() as RenderBox;
    Size size = box!.size;
    Offset position = box.localToGlobal(Offset.zero);
    _overlayEntry = OverlayEntry(
      builder: (context) => Positioned(
        top: size.height + position.dy,
        left: position.dx,
        child: Card(
          child: Container(
              height: 200,
              width: size.width,
              decoration: BoxDecoration(
                border: Border.all(),
              ),
              child: Column(
                children: [
                  Container(
                    width: size.width,
                    child: IconButton(
                      onPressed: () {
                        if (_overlayEntry.mounted) {
                          _overlayEntry.remove();
                        }
                      },
                      icon: Icon(Icons.close),
                      alignment: Alignment.topRight,
                    ),
                  ),
                  Expanded(
                    child: ListView(
                      children: []..addAll(List.generate(
                          200, (index) => Text(index.toString()))),
                    ),
                  ),
                ],
              )),
        ),
      ),
    );
    state!.insert(_overlayEntry);
  }

  final key = GlobalKey();
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: const EdgeInsets.all(50),
        child: Column(
          children: [
            TextField(
              key: key,
              onChanged: (String searchText) {
                if (_debounce?.isActive ?? false) _debounce!.cancel();
                _debounce = Timer(const Duration(milliseconds: 500), () {
                  print(searchText);
                });
              },
            ),
            ElevatedButton(
              onPressed: () {
                _showOverlay(context);
              },
              child: Text('Press Me'),
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          if (_overlayEntry.mounted) {
            _overlayEntry.remove();
          }
        },
      ),
    );
  }
}

enter image description here


-2

没有必要一次性获取所有数据,这更像是自动完成。API将根据用户输入的文本返回结果。 - Yaseen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接