如何实现Tabbar中每个标签页的搜索动作

How to implement the search action for each tab in Tabbar

我有一个页面在TabBar中有2个标签,如下:

class SearchByCityOrPerson extends StatefulWidget {


 SearchByCityOrPerson({Key key, this.title}) : super(key: key);

  final String title;

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

class _SearchByCityOrPerson extends State<SearchByCityOrPerson> {

  List<String> _cities = ['Albania', 'Andorra', 'Armenia', 'Austria',
    'Azerbaijan', 'Belarus', 'Belgium', 'Bosnia and Herzegovina', 'Bulgaria',
    'Croatia', 'Cyprus', 'Czech Republic', 'Denmark', 'Estonia', 'Finland',
    'France', 'Georgia', 'Germany', 'Greece', 'Hungary', 'Iceland', 'Ireland',
    'Italy', 'Kazakhstan', 'Kosovo', 'Latvia', 'Liechtenstein', 'Lithuania',
    'Luxembourg', 'Macedonia', 'Malta', 'Moldova', 'Monaco', 'Montenegro',
    'Netherlands', 'Norway', 'Poland', 'Portugal', 'Romania', 'Russia',
    'San Marino', 'Serbia', 'Slovakia', 'Slovenia', 'Spain', 'Sweden',
    'Switzerland', 'Turkey', 'Ukraine', 'United Kingdom', 'Vatican City'];

  List<String> _persons = ["John Smith", "Alex Johnson", "Jane Doe", "Eric Johnson", "Michael Eastwood", "Benjamin Woods"];

  List<String> _filteredList = [];      
  TextEditingController controller = new TextEditingController();

  String filter = "";
  Icon actionIcon = new Icon(Icons.search);
  Widget appBarTitle = new Text("Search...");



  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  @override
  void initState() {
   setState(() {          
      _filteredList = _cities;
    });
    controller.addListener(() {
      if (controller.text.isEmpty) {
        setState(() {
          filter = "";
          _filteredList = _cities;
        });
      } else {
        setState(() {
          filter = controller.text;
        });
      }
    });
    super.initState();
  }


  @override
  Widget build(BuildContext context) {
    ListTile personListTile(String bookOrPerson) =>
        ListTile(
          title: Text(
            bookOrPerson,
            style: TextStyle(
                color: Colors.black45, fontWeight: FontWeight.bold),
          ),);

    Card personCard(bookOrPeson) =>
        Card(
          child: Container(
            decoration: BoxDecoration(color: Colors.grey[300]),
            child: personListTile(bookOrPeson),
          ),
        );

    if ((filter.isNotEmpty)) {
      List<String> tmpList = new List<String>();
      for (int i = 0; i < _filteredList.length; i++) {
        if (_filteredList[i].toLowerCase().contains(
            filter.toLowerCase())) {
          tmpList.add(_filteredList[i]);
        }
      }
      _filteredList = tmpList;
    }

    final appBody = Container(
      child: ListView.builder(
        scrollDirection: Axis.vertical,
        shrinkWrap: true,
        itemCount: _cities == null ? 0 : _filteredList.length,
        itemBuilder: (BuildContext context, int index) {
          return personCard(_filteredList[index]);
        },
      ),
    );

    final appTopAppBar = AppBar(
      elevation: 0.1,
      bottom: TabBar(
        tabs: [
          GestureDetector(
            child: Text("City"),
            onTap: (){
              _filteredList = _cities;
            },
          ),

          GestureDetector(
            child: Text("Person"),
            onTap: (){
              _filteredList = _persons;
            },
          ),
        ]
      ),
      title: appBarTitle,
      actions: <Widget>[
        new IconButton(
          icon: actionIcon,
          onPressed: () {
            setState(() {
              if (this.actionIcon.icon == Icons.search) {
                this.actionIcon = new Icon(Icons.close);
                this.appBarTitle = new TextField(
                  controller: controller,
                  decoration: new InputDecoration(
                    /*prefixIcon: new Icon(Icons.search, color: Colors.white),*/
                    hintText: "Search...",
                    hintStyle: new TextStyle(color: Colors.white),
                  ),
                  style: new TextStyle(
                    color: Colors.white,
                  ),
                  autofocus: true,
                  cursorColor: Colors.white,
                );
              } else {
                this.actionIcon = new Icon(Icons.search);
                this.appBarTitle = new Text("Cities");
                _filteredList = _cities;
                controller.clear();
              }
            });
          },
        ),
      ],
    );

    return DefaultTabController(
      length: 2,
      child: Scaffold(
        appBar: appTopAppBar,
        body: appBody,
      ),
    );
  }

}

正如您在屏幕截图中看到的那样,问题是当第二个选项卡 "Search by Person" 选项被选中时,它应该显示所有人员列表并允许用户按人名搜索,我试过了在每个选项卡的 on tab 方法中实现它,但它需要以某种方式刷新,我想有更好的方法来实现它,考虑到列表 [=19= 我应该如何实现它]_c​​ities_persons 将在将来进行 api 调用时加载。

这是我经过一个小时后所做的事情

  1. Added a TabBar View in Body to show person lists in second tabs.
  2. for search, honestly, I did nothing .. I just added the same code you did but with person lists.
  3. I removed DefaultTabController and added controller for an index, so that you can get a different title for different TabBar.

代码如下

class SearchByCityOrPerson extends StatefulWidget {


  SearchByCityOrPerson({Key key, this.title}) : super(key: key);

  final String title;

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

class _SearchByCityOrPerson extends State<SearchByCityOrPerson> with SingleTickerProviderStateMixin {

  List<String> _cities = ['Albania', 'Andorra', 'Armenia', 'Austria',
    'Azerbaijan', 'Belarus', 'Belgium', 'Bosnia and Herzegovina', 'Bulgaria',
    'Croatia', 'Cyprus', 'Czech Republic', 'Denmark', 'Estonia', 'Finland',
    'France', 'Georgia', 'Germany', 'Greece', 'Hungary', 'Iceland', 'Ireland',
    'Italy', 'Kazakhstan', 'Kosovo', 'Latvia', 'Liechtenstein', 'Lithuania',
    'Luxembourg', 'Macedonia', 'Malta', 'Moldova', 'Monaco', 'Montenegro',
    'Netherlands', 'Norway', 'Poland', 'Portugal', 'Romania', 'Russia',
    'San Marino', 'Serbia', 'Slovakia', 'Slovenia', 'Spain', 'Sweden',
    'Switzerland', 'Turkey', 'Ukraine', 'United Kingdom', 'Vatican City'];

  List<String> _persons = ["John Smith", "Alex Johnson", "Jane Doe", "Eric Johnson", "Michael Eastwood", "Benjamin Woods"];

  List<String> _filteredList = [];

  List<String> _personsList = [];

  TextEditingController controller = new TextEditingController();

  TabController _tabController;

  String filter = "";
  String persons = "";
  Icon actionIcon = new Icon(Icons.search);
  Widget appBarTitle = new Text("Search...");


  void _handleTabIndex() {
    setState(() {});
  }

  @override
  void dispose() {
    controller.dispose();
    _tabController.removeListener(_handleTabIndex);
    _tabController.dispose();
    super.dispose();
  }

  @override
  void initState() {
    _tabController = TabController(length: 2, vsync: this, initialIndex: 0);
    _tabController.addListener(_handleTabIndex);
    setState(() {
      _filteredList = _cities;
      _personsList = _persons;
    });
    controller.addListener(() {
      if (controller.text.isEmpty) {
        setState(() {
          filter = "";
          persons = "";
          _filteredList = _cities;
          _personsList = _persons;
        });
      } else {
        setState(() {
          filter = controller.text;
          persons = controller.text;
        });
      }
    });
    super.initState();
  }


  @override
  Widget build(BuildContext context) {
    ListTile personListTile(String bookOrPerson) =>
        ListTile(
          title: Text(
            bookOrPerson,
            style: TextStyle(
                color: Colors.black45, fontWeight: FontWeight.bold),
          ),);
    Card personCard(bookOrPerson) => Card(
      child: Container(
        decoration: BoxDecoration(color: Colors.grey[300]),
        child: personListTile(bookOrPerson),
      ),
    );

    if ((filter.isNotEmpty)) {
      List<String> tmpList = new List<String>();
      for (int i = 0; i < _filteredList.length; i++) {
        if (_filteredList[i].toLowerCase().contains(
            filter.toLowerCase())) {
          tmpList.add(_filteredList[i]);
        }
      }
      _filteredList = tmpList;
    }

    if ((persons.isNotEmpty)) {
      List<String> _tmpList2 = new List<String>();
      for (int i = 0; i < _personsList.length; i++) {
        if (_personsList[i].toLowerCase().contains(
            persons.toLowerCase())) {
          _tmpList2.add(_personsList[i]);
        }
      }
      _personsList = _tmpList2;
    }

    final appBody = TabBarView(
      controller: _tabController,
        children: [
          Container(
            child: ListView.builder(
              scrollDirection: Axis.vertical,
              shrinkWrap: true,
              itemCount: _cities == null ? 0 : _filteredList.length,
              itemBuilder: (BuildContext context, int index) {
                return personCard(_filteredList[index]);
              },
            ),
          ),

          Container(
            child: ListView.builder(
              scrollDirection: Axis.vertical,
              shrinkWrap: true,
              itemCount: _persons == null ? 0 : _personsList.length,
              itemBuilder: (BuildContext context, int index) {
                return personCard(_personsList[index]);
              },
            ),
          ),
        ]);

    final appTopAppBar = AppBar(
      elevation: 0.1,
      bottom: TabBar(
          controller: _tabController,
          tabs: [
            Tab( text: "City"),
            Tab(text: "person")


          ]
      ),
      title: appBarTitle,
      actions: <Widget>[
        new IconButton(
          icon: actionIcon,
          onPressed: () {
            setState(() {
              if (this.actionIcon.icon == Icons.search) {
                this.actionIcon = new Icon(Icons.close);
                this.appBarTitle = new TextField(
                  controller: controller,
                  decoration: new InputDecoration(
                    /*prefixIcon: new Icon(Icons.search, color: Colors.white),*/
                    hintText: "Search...",
                    hintStyle: new TextStyle(color: Colors.white),
                  ),
                  style: new TextStyle(
                    color: Colors.white,
                  ),
                  autofocus: true,
                  cursorColor: Colors.white,
                );
              } else {
                this.actionIcon = new Icon(Icons.search);
                this.appBarTitle = new Text(_tabController.index == 0 ? "Cities" : "Persons");
                _filteredList = _cities;
                _personsList = _persons;
                controller.clear();
              }
            });
          },
        ),
      ],
    );

    return
      Scaffold(
        appBar: appTopAppBar,
        body: appBody,



      );



  }

}