首页 > 解决方案 > 带有自动完成功能的 Flutter 搜索栏

问题描述

我正在寻找颤振文档中的搜索栏但找不到它,是否有用于搜索栏的小部件,在 appbar 中具有自动完成功能。例如,我的应用栏上有一个搜索图标。一按它就会显示搜索框,当您键入它时,它应该会从带有 listtile 的下拉列表中显示自动完成。我设法实现了这一点,但它并不容易使用,因为我需要一个下拉列表来显示建议自动完成,然后在选择时使用新路线的建议。

这里是搜索动作

这是我想要实现的示例图像

标签: flutterdartsearch

解决方案


你可以使用 Stack 来实现自动完成的下拉框效果。下面的示例有 2 个容器 - 都ListView作为子对象保存。一个包含搜索结果,另一个包含一些随机文本作为正文的内容。ListView(搜索结果)放置在对齐对象内,对齐属性设置为 Alignment.topCenter。这样可以确保 List 出现在顶部,就在AppBar.

更新了评论中提到的帖子(已接受的答案)以获得完整的演示。

如上所述:

    @override
      Widget build(BuildContext context) {
        return new Scaffold(
            key: key,
            appBar: buildBar(context),
            body: new Stack(
              children: <Widget>[
                new Container(
                  height: 300.0,
                  padding: EdgeInsets.all(10.0),
                  child: new DefaultTabController(length: 5, child: mainTabView),
                ),
                displaySearchResults(),
              ],
            ));
      }


      Widget displaySearchResults() {
        if (_IsSearching) {
          return new Align(
              alignment: Alignment.topCenter,
              //heightFactor: 0.0,
              child: searchList());
        } else {
          return new Align(alignment: Alignment.topCenter, child: new Container());
        }
      }

完整的演示

class SearchList extends StatefulWidget {
  SearchList({Key key, this.name}) : super(key: key);

  final String name;

  @override
  _SearchListState createState() => new _SearchListState();
}

class _SearchListState extends State<SearchList> {
  Widget appBarTitle = new Text(
    "",
    style: new TextStyle(color: Colors.white),
  );
  Icon actionIcon = new Icon(
    Icons.search,
    color: Colors.white,
  );
  final key = new GlobalKey<ScaffoldState>();
  final TextEditingController _searchQuery = new TextEditingController();
  List<SearchResult> _list;
  bool _IsSearching;
  String _searchText = "";
  String selectedSearchValue = "";

  _SearchListState() {
    _searchQuery.addListener(() {
      if (_searchQuery.text.isEmpty) {
        setState(() {
          _IsSearching = false;
          _searchText = "";
        });
      } else {
        setState(() {
          _IsSearching = true;
          _searchText = _searchQuery.text;
        });
      }
    });
  }

  @override
  void initState() {
    super.initState();
    _IsSearching = false;
    createSearchResultList();
  }

  void createSearchResultList() {
    _list = <SearchResult>[
      new SearchResult(name: 'Google'),
      new SearchResult(name: 'IOS'),
      new SearchResult(name: 'IOS2'),
      new SearchResult(name: 'Android'),
      new SearchResult(name: 'Dart'),
      new SearchResult(name: 'Flutter'),
      new SearchResult(name: 'Python'),
      new SearchResult(name: 'React'),
      new SearchResult(name: 'Xamarin'),
      new SearchResult(name: 'Kotlin'),
      new SearchResult(name: 'Java'),
      new SearchResult(name: 'RxAndroid'),
    ];
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        key: key,
        appBar: buildBar(context),
        body: new Stack(
          children: <Widget>[
            new Container(
              height: 300.0,
              padding: EdgeInsets.all(10.0),
              child: new Container(
                child: ListView(
                  children: <Widget>[
                    new Text("Hello World!"),
                    new Text("Hello World!"),
                    new Text("Hello World!"),
                    new Text("Hello World!"),
                    new Text("Hello World!"),
                    new Text("Hello World!"),
                    new Text("Hello World!"),
                    new Text("Hello World!"),
                    new Text("Hello World!"),
                    new Text("Hello World!"),
                    new Text("Hello World!"),
                    new Text("Hello World!"),
                    new Text("Hello World!"),
                  ],
                ),
              ),
            ),
            displaySearchResults(),
          ],
        ));
  }

  Widget displaySearchResults() {
    if (_IsSearching) {
      return new Align(
          alignment: Alignment.topCenter,
          child: searchList());
    } else {
      return new Align(alignment: Alignment.topCenter, child: new Container());
    }
  }

  ListView searchList() {
    List<SearchResult> results = _buildSearchList();
    return ListView.builder(
      itemCount: _buildSearchList().isEmpty == null ? 0 : results.length,
      itemBuilder: (context, int index) {
        return Container(
          decoration: new BoxDecoration(
              color: Colors.grey[100],
            border: new Border(
              bottom: new BorderSide(
                  color: Colors.grey,
                width: 0.5
              )
          )
          ),

          child: ListTile(
            onTap: (){},
            title: Text(results.elementAt(index).name,
                style: new TextStyle(fontSize: 18.0)),
          ),
        );
      },
    );
  }

  List<SearchResult> _buildList() {
    return _list.map((result) => new SearchResult(name: result.name)).toList();
  }

  List<SearchResult> _buildSearchList() {
    if (_searchText.isEmpty) {
      return _list.map((result) => new SearchResult(name: result.name)).toList();
    } else {
      List<SearchResult> _searchList = List();
      for (int i = 0; i < _list.length; i++) {
        SearchResult result = _list.elementAt(i);
        if ((result.name).toLowerCase().contains(_searchText.toLowerCase())) {
          _searchList.add(result);
        }
      }
      return _searchList
          .map((result) => new SearchResult(name: result.name))
          .toList();
    }
  }

  Widget buildBar(BuildContext context) {
    return new AppBar(
      centerTitle: true,
      title: appBarTitle,
      actions: <Widget>[
        new IconButton(
          icon: actionIcon,
          onPressed: () {
            _displayTextField();
          },
        ),

        // new IconButton(icon: new Icon(Icons.more), onPressed: _IsSearching ? _showDialog(context, _buildSearchList()) : _showDialog(context,_buildList()))
      ],
    );
  }

  String selectedPopupRoute = "My Home";
  final List<String> popupRoutes = <String>[
    "My Home",
    "Favorite Room 1",
    "Favorite Room 2"
  ];

  void _displayTextField() {
    setState(() {
      if (this.actionIcon.icon == Icons.search) {
        this.actionIcon = new Icon(
          Icons.close,
          color: Colors.white,
        );
        this.appBarTitle = new TextField(
          autofocus: true,
          controller: _searchQuery,
          style: new TextStyle(
            color: Colors.white,
          ),
        );

        _handleSearchStart();
      } else {
        _handleSearchEnd();
      }
    });
  }

  void _handleSearchStart() {
    setState(() {
      _IsSearching = true;
    });
  }

  void _handleSearchEnd() {
    setState(() {
      this.actionIcon = new Icon(
        Icons.search,
        color: Colors.white,
      );
      this.appBarTitle = new Text(
        "",
        style: new TextStyle(color: Colors.white),
      );
      _IsSearching = false;
      _searchQuery.clear();
    });
  }
}

推荐阅读