首页 > 解决方案 > 搜索栏在 draggablescrollablesheet (Flutter) 中无法正常工作

问题描述

我是 Flutter 新手。我在可拖动的底部表单中使用自己的搜索栏时遇到了问题。当从主屏幕单击搜索字段时,我创建了一个可拖动的底部工作表来搜索信息。我在工作表中添加了一个搜索栏和一个列表视图,但搜索栏无法正常工作。它不能立即过滤掉数据,它只是在关闭键盘时显示结果。请任何人帮助我。

class AddPersonalInfo extends StatefulWidget {
  final String mail, password;
  const AddPersonalInfo({Key? key, required this.mail, required this.password})
      : super(key: key);

  @override
  _AddPersonalInfoState createState() => _AddPersonalInfoState();
}

class _AddPersonalInfoState extends State<AddPersonalInfo> {
  TextEditingController _search = TextEditingController();

  List<City> cites = [
    City(id: 1, code: "HN", name: "Ha Noi"),
    City(id: 2, code: "HCM", name: "Ho CHi Minh"),
    City(id: 3, code: "DN", name: "Da Nang"),
    City(id: 4, code: "HP", name: "Hai Phong"),
    City(id: 5, code: "CT", name: "Can Tho"),
    City(id: 6, code: "DNN", name: "Dong Nai"),
    City(id: 7, code: "KH", name: "Khanh Hoa"),
    City(id: 8, code: "PY", name: "Phu Yen"),
    City(id: 9, code: "NT", name: "Nha Trang"),
    City(id: 10, code: "VL", name: "Vinh Long"),
    City(id: 11, code: "HD", name: "Hai Duong"),
    City(id: 12, code: "BD", name: "Binh Duong")
  ];

  City? selected;

  List<City> foundCity = [];

  @override
  void initState() {
    super.initState();

    setState(() {
      foundCity = cites;
    });
  }

  @override
  Widget build(BuildContext context) {
    Size screenSize = MediaQuery.of(context).size;
    Orientation orientation = MediaQuery.of(context).orientation;

    return GestureDetector(
      onTap: () {
        FocusScope.of(context).unfocus();
      },
      child: Scaffold(
        backgroundColor: Colors.white,
        body: SafeArea(
          child: LayoutBuilder(builder: (context, snapshot) {
            if (snapshot.maxWidth <= screenSize.width &&
                orientation == Orientation.portrait) {
              return SingleChildScrollView(
                scrollDirection: Axis.vertical,
                child: Container(
                  padding: EdgeInsets.fromLTRB(30 * screenScale(context), 0,
                      30 * screenScale(context), 0),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: [
                      Stack(
                        children: [
                          Container(
                            alignment: Alignment.topCenter,
                            padding: EdgeInsets.only(
                                bottom: 20 * screenScale(context)),
                            child: introText("Create account", context),
                          ),
                          backBtn(context),
                        ],
                      ),
                      mainText(
                          "Let's create an account to grab all latest gadgets and enjoy the best experiences.",
                          context),
                      Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [_fnameField(), _lnameField()],
                      ),
                      _phoneField(),
                      GestureDetector(
                        onTap: () => showModalBottomSheet(
                          backgroundColor: Colors.transparent,
                          isScrollControlled: true,
                          context: context,
                          builder: (context) => buildSheet(),
                        ),
                        child: Container(
                          height: 50,
                          margin: EdgeInsets.only(top: 15),
                          padding: EdgeInsets.only(left: 10, right: 7),
                          decoration: BoxDecoration(
                            border: Border.all(color: Colors.grey),
                            borderRadius: BorderRadius.circular(7),
                          ),
                          child: Row(
                            mainAxisAlignment: MainAxisAlignment.spaceBetween,
                            children: [
                              selected == null
                                  ? Text("Select city",
                                      style: TextStyle(
                                          fontSize: 16,
                                          color: Colors.grey.shade700))
                                  : Text("${selected!.name}",
                                      style: TextStyle(
                                          fontSize: 16, color: Colors.black)),
                              Icon(Ionicons.chevron_down_outline, size: 24)
                            ],
                          ),
                        ),
                      )
                    ],
                  ),
                ),
              );
            } else {
              return SingleChildScrollView(
                scrollDirection: Axis.vertical,
                child: Container(
                  padding: EdgeInsets.fromLTRB(30 * screenScale(context), 0,
                      30 * screenScale(context), 0),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: [],
                  ),
                ),
              );
            }
          }),
        ),
      ),
    );
  }

  Widget buildSheet() {
    return GestureDetector(
      behavior: HitTestBehavior.opaque,
      onTap: () {
        Navigator.of(context).pop();
      },
      child: DraggableScrollableSheet(
        initialChildSize: 0.9,
        builder: (_, controller) => Container(
          padding: EdgeInsets.fromLTRB(10, 10, 10, 0),
          decoration: BoxDecoration(
            color: Colors.white,
            borderRadius: BorderRadius.vertical(
              top: Radius.circular(20),
            ),
          ),
          child: Column(
            children: [
              Divider(
                thickness: 4,
                color: Colors.grey.shade300,
                endIndent: 170,
                indent: 170,
              ),
              Padding(
                padding: EdgeInsets.only(bottom: 15, top: 5),
                child: Text("Select city",
                    style: TextStyle(
                        fontSize: 18,
                        color: Colors.black,
                        fontWeight: FontWeight.bold)),
              ),
              Padding(
                padding: EdgeInsets.only(bottom: 10),
                child: TextFormField(
                  controller: _search,
                  keyboardType: TextInputType.name,
                  style: TextStyle(fontSize: 16 * fontScale(context)),
                  decoration: InputDecoration(
                    border: OutlineInputBorder(
                        borderRadius:
                            BorderRadius.circular(7 * screenScale(context))),
                    contentPadding:
                        EdgeInsets.only(top: 10 * screenScale(context)),
                    hintText: 'Search',
                    prefixIcon: Icon(Ionicons.search_outline),
                  ),
                  onChanged: (value) {
                    setState(() {
                      foundCity = cites
                          .where(
                              (city) => city.name.toLowerCase().contains(value))
                          .toList();
                    });
                  },
                ),
              ),
              Expanded(
                child: foundCity.length > 0
                    ? ListView.builder(
                        itemCount: foundCity.length,
                        itemBuilder: (context, index) {
                          final city = foundCity[index];
                          return ListTile(
                            title: Text(city.name),
                            onTap: () {
                              Navigator.of(context).pop();
                              setState(() {
                                selected = city;
                              });
                            },
                          );
                        },
                      )
                    : Padding(
                        padding: EdgeInsets.only(top: 50),
                        child: Text(
                          "No data.",
                          style: TextStyle(fontSize: 16),
                        ),
                      ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

标签: flutter

解决方案


好的,我检查了您的代码,似乎您错过了一个小问题,当您创建 showModalBottomSheet 时,它不再是您的有状态小部件的一部分

我已经调整了代码,使其现在可以工作:

 Widget buildSheet(BuildContext context) {
    return StatefulBuilder(builder: (BuildContext context, setState) {
      return GestureDetector(
        behavior: HitTestBehavior.opaque,
        onTap: () {
          Navigator.of(context).pop();
        },
        child: DraggableScrollableSheet(
          initialChildSize: 0.9,
          builder: (_, controller) => Container(
            padding: EdgeInsets.fromLTRB(10, 10, 10, 0),
            decoration: BoxDecoration(
              color: Colors.white,
              borderRadius: BorderRadius.vertical(
                top: Radius.circular(20),
              ),
            ),
            child: Column(
              children: [
                Divider(
                  thickness: 4,
                  color: Colors.grey.shade300,
                  endIndent: 170,
                  indent: 170,
                ),
                Padding(
                  padding: EdgeInsets.only(bottom: 15, top: 5),
                  child: Text("Select city",
                      style: TextStyle(
                          fontSize: 18,
                          color: Colors.black,
                          fontWeight: FontWeight.bold)),
                ),
                Padding(
                  padding: EdgeInsets.only(bottom: 10),
                  child: TextFormField(
                    controller: _search,
                    keyboardType: TextInputType.name,
                    style: TextStyle(fontSize: 16),
                    decoration: InputDecoration(
                      border: OutlineInputBorder(
                          borderRadius: BorderRadius.circular(7)),
                      contentPadding: EdgeInsets.only(top: 10),
                      hintText: 'Search',
                      prefixIcon: Icon(Icons.access_alarm),
                    ),
                    onChanged: (value) {
                      setState(() {
                        foundCity = cites
                            .where((city) =>
                                city.name!.toLowerCase().contains(value))
                            .toList();
                      });
                    },
                  ),
                ),
                Expanded(
                  child: foundCity.isNotEmpty
                      ? ListView.builder(
                          itemCount: foundCity.length,
                          itemBuilder: (context, index) {
                            final city = foundCity[index];
                            return ListTile(
                              title: Text(city.name!),
                              onTap: () {
                                Navigator.of(context).pop();
                                setState(() {
                                  selected = city;
                                });
                              },
                            );
                          },
                        )
                      : Padding(
                          padding: EdgeInsets.only(top: 50),
                          child: Text(
                            "No data.",
                            style: TextStyle(fontSize: 16),
                          ),
                        ),
                ),
              ],
            ),
          ),
        ),
      );
    });
  }

推荐阅读