Flutter 可见性切换未按预期工作

Flutter Visibility Toggle not working as expected

创建一个我想执行 Flutter-FireBase 的屏幕Searching.But可见性切换未按预期工作。
所需的切换行为:单击 TextForm 字段时,应该可以看到前缀图标和结果卡。单击前缀图标(后退箭头)后,结果列表(卡片)和前缀图标本身应该变得不可见,TextField 应该取消焦点。
实际行为:单击前缀图标时,结果集和前缀图标不会消失,前缀图标保留在那里,结果集变得不可见但占用一些 space 在 TextFormField

下面
class AddAppointmentWidget extends StatefulWidget {
  @override
  _AddAppointmentWidgetState createState() => _AddAppointmentWidgetState();
}

class _AddAppointmentWidgetState extends State<AddAppointmentWidget> {
  bool searchbartapped = false;
  var queryResultSet = [];
  var tempSearchStore = [];

// Search Function
  initiateSearch(value) {
    //body
  }

  @override
  Widget build(BuildContext context) {
    return ListView(
      children: [
        SizedBox(
          height: 15,
        ),
        Padding(
          padding: const EdgeInsets.all(18.0),
          child: Text('Search',
              style: TextStyle(fontSize: 35, fontWeight: FontWeight.bold)),
        ),
        Padding(
          padding: const EdgeInsets.all(8.0),
          child: Row(
            children: [
              Expanded(
                flex: 5,
                child: TextFormField(
                    style: TextStyle(color: Color(0xff2a2a2a), fontSize: 18),
                    keyboardType: TextInputType.name,
                    onChanged: (value) {
                      initiateSearch(value);
                    },
                    onTap: () {
                      setState(() {
                        searchbartapped = true;
                      });
                    },
                    cursorColor: Color(0xff2a2a2a),
                    cursorWidth: 1.5,
                    decoration: InputDecoration(
                        hintText: "Search by Name",
                        prefixIcon: Visibility(
                          visible: searchbartapped,
                          child: IconButton(
                              icon: Icon(Icons.arrow_back),
                              color: Colors.black54,
                              onPressed: () {
                                setState(() {
                                  searchbartapped = !searchbartapped;
                                  queryResultSet = [];
                                  tempSearchStore = [];
                                });
                                FocusScope.of(context).unfocus();
                              }),
                        ),
                        )),
              ),
            ],
          ),
        ),
        Visibility(
          visible: searchbartapped,
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: ListView(
                padding: EdgeInsets.all(5.0),
                primary: false,
                shrinkWrap: true,
                children: tempSearchStore.map((element) {
                  print(element['name']);
                  return buildResult(context, element);
                }).toList()),
          ),
        ),
      ],
    );
  }
}

注意 buildResult 小部件运行良好。 问题仅在于可见性切换

问题: 当您点击 prefixIcon

  1. onPressed 被调用,将 searchbartapped 设置为 false,这就是您想要的。
  2. 你的TextFormFieldonTap方法也被调用(因为prefixIcon在里面),设置searchbartappedtrue.

所以你想要的是防止第二件事发生。我试图阻止通知在树上冒泡,但我做不到。所以我最终做的是更多的手动操作,但效果也一样。

解决方案: 添加一个变量(例如hideSearchTapped),在调用prefixIcon 时设置为true。然后当你的TextFormFieldonTap方法被调用时,检查这个变量:

  • 如果 hideSearchTapped 为真,则将其设置为假
  • 否则像你一样改变searchbartapped

这是一个工作示例:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() async {
  runApp(
    MaterialApp(
      home: Scaffold(
        body: new AddAppointmentWidget(),
      ),
    ),
  );
}

class AddAppointmentWidget extends StatefulWidget {
  @override
  _AddAppointmentWidgetState createState() => _AddAppointmentWidgetState();
}

class _AddAppointmentWidgetState extends State<AddAppointmentWidget> {
  bool searchbartapped = false;
  bool hideSearchTapped = false;
  var queryResultSet = [];
  var tempSearchStore = [];

// Search Function
  initiateSearch(value) {
    //body
  }

  @override
  Widget build(BuildContext context) {
    return ListView(
      children: [
        SizedBox(
          height: 15,
        ),
        Padding(
          padding: const EdgeInsets.all(18.0),
          child: Text('Search', style: TextStyle(fontSize: 35, fontWeight: FontWeight.bold)),
        ),
        Padding(
          padding: const EdgeInsets.all(8.0),
          child: Row(
            children: [
              Expanded(
                flex: 5,
                child: TextFormField(
                    style: TextStyle(color: Color(0xff2a2a2a), fontSize: 18),
                    keyboardType: TextInputType.name,
                    onChanged: (value) {
                      initiateSearch(value);
                    },
                    onTap: () {
                      setState(() {
                        if (hideSearchTapped) {
                          hideSearchTapped = false;
                        } else {
                          searchbartapped = true;
                        }
                      });
                    },
                    cursorColor: Color(0xff2a2a2a),
                    cursorWidth: 1.5,
                    decoration: InputDecoration(
                      hintText: "Search by Name",
                      prefixIcon: Visibility(
                        visible: searchbartapped,
                        child: IconButton(
                            icon: Icon(Icons.arrow_back),
                            color: Colors.black54,
                            onPressed: () {
                              hideSearchTapped = true;
                              searchbartapped = !searchbartapped;
                              queryResultSet = [];
                              tempSearchStore = [];
                              setState(() {
                              });
                              FocusScope.of(context).unfocus();
                              return true;
                            }),
                      ),
                    )),
              ),
            ],
          ),
        ),
        Visibility(
          visible: searchbartapped,
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: ListView(
                padding: EdgeInsets.all(5.0),
                primary: false,
                shrinkWrap: true,
                children: tempSearchStore.map((element) {
                  print(element['name']);
                }).toList()),
          ),
        ),
      ],
    );
  }
}

注意:你应该use lowerCamelCase to name your variable。所以 searchbartapped 会变成 searchBarTapped.