如何在颤振中创建工具栏搜索视图

Posted

技术标签:

【中文标题】如何在颤振中创建工具栏搜索视图【英文标题】:how to create toolbar searchview in flutter 【发布时间】:2018-10-02 16:00:06 【问题描述】:

我需要在我的应用程序的工具栏中实现 searchview 以实现列表视图列表过滤。如下图,我搜索了很多仍然没有得到正确的答案。任何帮助将不胜感激,在此先感谢您。

【问题讨论】:

如果这个问题重复,请告诉我或请告诉我为什么不赞成这个问题 您可以使用 Flutter 库来实现与 Youtube/Instagram 相同的设计:github.com/pkmangukiya/flutter_search_view_pk 【参考方案1】:

在@aziza 回答的帮助下,我用下面的列表过滤器编写了搜索视图的详细代码 sn-p。它会帮助别人

import 'package:flutter/material.dart';

class SearchList extends StatefulWidget 
  SearchList( Key key ) : super(key: key);
  @override
  _SearchListState createState() => new _SearchListState();



class _SearchListState extends State<SearchList>

  Widget appBarTitle = new Text("Search Sample", 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<String> _list;
  bool _IsSearching;
  String _searchText = "";

  _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;
    init();

  

  void init() 
    _list = List();
    _list.add("Google");
    _list.add("ios");
    _list.add("Andorid");
    _list.add("Dart");
    _list.add("Flutter");
    _list.add("Python");
    _list.add("React");
    _list.add("Xamarin");
    _list.add("Kotlin");
    _list.add("Java");
    _list.add("Rxandroid");
  

  @override
  Widget build(BuildContext context) 
    return new Scaffold(
      key: key,
      appBar: buildBar(context),
      body: new ListView(
        padding: new EdgeInsets.symmetric(vertical: 8.0),
        children: _IsSearching ? _buildSearchList() : _buildList(),
      ),
    );
  

  List<ChildItem> _buildList() 
    return _list.map((contact) => new ChildItem(contact)).toList();
  

  List<ChildItem> _buildSearchList() 
    if (_searchText.isEmpty) 
      return _list.map((contact) => new ChildItem(contact))
          .toList();
    
    else 
      List<String> _searchList = List();
      for (int i = 0; i < _list.length; i++) 
        String  name = _list.elementAt(i);
        if (name.toLowerCase().contains(_searchText.toLowerCase())) 
          _searchList.add(name);
        
      
      return _searchList.map((contact) => new ChildItem(contact))
          .toList();
    
  

  Widget buildBar(BuildContext context) 
    return new AppBar(
        centerTitle: true,
        title: appBarTitle,
        actions: <Widget>[
          new IconButton(icon: actionIcon, onPressed: () 
            setState(() 
              if (this.actionIcon.icon == Icons.search) 
                this.actionIcon = new Icon(Icons.close, color: Colors.white,);
                this.appBarTitle = new TextField(
                  controller: _searchQuery,
                  style: new TextStyle(
                    color: Colors.white,

                  ),
                  decoration: new InputDecoration(
                      prefixIcon: new Icon(Icons.search, color: Colors.white),
                      hintText: "Search...",
                      hintStyle: 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("Search Sample", style: new TextStyle(color: Colors.white),);
      _IsSearching = false;
      _searchQuery.clear();
    );
  



class ChildItem extends StatelessWidget 
  final String name;
  ChildItem(this.name);
  @override
  Widget build(BuildContext context) 
    return new ListTile(title: new Text(this.name));
  


输出:

【讨论】:

为了运行上面的代码,请更新'Widget build'方法:return new MediaQuery(data: new MediaQueryData(), child: new MaterialApp(home: new Scaffold..... ....【参考方案2】:

您只需要在用户点击图标时在状态之间切换。除了一点点重构代码清理之外,这个简单的示例应该可以帮助您进行。

class SearchAppBar extends StatefulWidget 
  @override
  _SearchAppBarState createState() => new _SearchAppBarState();


class _SearchAppBarState extends State<SearchAppBar> 
  Widget appBarTitle = new Text("AppBar Title");
  Icon actionIcon = new Icon(Icons.search);
  @override
  Widget build(BuildContext context) 
    return new Scaffold(
      appBar: new AppBar(
        centerTitle: true,
        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(
                        style: new TextStyle(
                          color: Colors.white,

                        ),
                        decoration: new InputDecoration(
                          prefixIcon: new Icon(Icons.search,color: Colors.white),
                          hintText: "Search...",
                          hintStyle: new TextStyle(color: Colors.white)
                        ),
                      );
                      else 
                        this.actionIcon = new Icon(Icons.search);
                        this.appBarTitle = new Text("AppBar Title");
                      


                    );
         ,),]
      ),
    );
  

【讨论】:

嗨 aziza,我如何处理文本查询更改和过滤列表?【参考方案3】:

如果你想要一个简单的搜索栏,你可以使用自定义的TextField

import 'package:flutter/material.dart';

class SearchBar extends StatelessWidget 
  final void Function(String) onTextChange;

  SearchBar( this.onTextChange );

  @override
  Widget build(BuildContext context) 
    return Container(
      height: 50,
      padding: EdgeInsets.all(8),
      child: TextField(
        onChanged: onTextChange,
        decoration: InputDecoration(
          fillColor: Colors.black.withOpacity(0.1),
          filled: true,
          prefixIcon: Icon(Icons.search),
          hintText: 'Search something ...',
          border: OutlineInputBorder(borderRadius: BorderRadius.circular(10), borderSide: BorderSide.none),
          contentPadding: EdgeInsets.zero
        )
      )
    );
  

【讨论】:

【参考方案4】:

屏幕截图(Null 安全):


您应该使用 Flutter 开箱即用的 SearchDelegate。这是一个小视频,它是如何工作的:

完整代码:

class SearchPage extends StatefulWidget 
  @override
  _SearchPageState createState() => _SearchPageState();


class _SearchPageState extends State<SearchPage> 
  String? _result;

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(title: Text('Search')),
      body: Center(
        child: Column(
          children: <Widget>[
            Text(_result ?? '', style: TextStyle(fontSize: 18)),
            ElevatedButton(
              onPressed: () async 
                var result = await showSearch<String>(
                  context: context,
                  delegate: CustomDelegate(),
                );
                setState(() => _result = result);
              ,
              child: Text('Search'),
            ),
          ],
        ),
      ),
    );
  


class CustomDelegate extends SearchDelegate<String> 
  List<String> data = nouns.take(100).toList();

  @override
  List<Widget> buildActions(BuildContext context) => [IconButton(icon: Icon(Icons.clear), onPressed: () => query = '')];

  @override
  Widget buildLeading(BuildContext context) => IconButton(icon: Icon(Icons.chevron_left), onPressed: () => close(context, ''));

  @override
  Widget buildResults(BuildContext context) => Container();

  @override
  Widget buildSuggestions(BuildContext context) 
    var listToShow;
    if (query.isNotEmpty)
      listToShow = data.where((e) => e.contains(query) && e.startsWith(query)).toList();
    else
      listToShow = data;

    return ListView.builder(
      itemCount: listToShow.length,
      itemBuilder: (_, i) 
        var noun = listToShow[i];
        return ListTile(
          title: Text(noun),
          onTap: () => close(context, noun),
        );
      ,
    );
  

【讨论】:

什么是名词? nouns 是我从this package使用的字符串列表 花了 2 个小时,但找到了一个非常有希望的解决方案。谢谢【参考方案5】:

您可以通过编辑 AppBar 的前导、标题和操作来完成。如下所示。

appBar: new AppBar(
    leading: _isSearching ? const BackButton() : null,
    title: _isSearching ? _buildSearchField() : _buildTitle(context),
    actions: _buildActions(),
 ),

你可以看到它here详细。他们为此构建了一个简单的演示。

【讨论】:

【参考方案6】:

还有 Flutter flutter_search_view_pk 库,您可以使用它来实现与 Youtube/Instagram 相同的设计。

如何集成和使用?

1:直接将pk_search_bar目录拖放到你的Flutter项目中。

2 : 创建Class SearchScreenbuild > Scaffold > child: SearchBar()

Navigator.push(
  context,
  MaterialPageRoute(
      builder: (context) =>  SearchScreen()),
);

示例

  Widget searchBar(BuildContext context) 
   return SearchBar<CountryModel>(
   searchBarPadding: EdgeInsets.only(left: 5, right: 5, top: 10, bottom: 5),
   headerPadding: EdgeInsets.only(left: 0, right: 0),
   listPadding: EdgeInsets.only(left: 0, right: 0),
   hintText: "Search Placeholder",
   hintStyle: TextStyle(
    color: Colors.black54,
  ),
  textStyle: TextStyle(
    color: Colors.black,
    fontWeight: FontWeight.normal,
  ),
  iconActiveColor: Colors.deepPurple,
  shrinkWrap: true,
  mainAxisSpacing: 5,
  crossAxisSpacing: 5,
  suggestions: widget.countryModelList,
  cancellationWidget: Text("Cancel"),
  minimumChars: 1,
  emptyWidget: Center(
    child: Padding(
      padding: const EdgeInsets.only(left: 10, right: 10),
      child: Text("There is no any data found"),
    ),
  ),
  onError: (error) 
    return Center(
      child: Padding(
        padding: const EdgeInsets.only(left: 10, right: 10),
        child: Text("$error", textAlign: TextAlign.center),
      ),
    );
  ,
  loader: Center(
    child: LoadingIndicator(),
  ),
  onSearch: getCountrySearchWithSuggestion, /// CountrySearch  // if 
   want to search with API then use thi ----> getCountryListFromApi
  onCancelled: () 
    Navigator.pop(context);
  ,
  buildSuggestion: (CountryModel countryModel, int index) 
    return countryGenerateColumn(countryModel, index);
  ,
  onItemFound: (CountryModel countryModel, int index) 
    return countryGenerateColumn(countryModel, index);
  ,
);

【讨论】:

以上是关于如何在颤振中创建工具栏搜索视图的主要内容,如果未能解决你的问题,请参考以下文章

如何在颤振中创建网页视图

在颤振中使用列表视图搜索数据时出错

如何使用颤振在网页视图中打开pdf文档

应该如何创建 UINavigation 工具栏子视图项 Interface Builder?

我如何更改搜索视图图标的颜色?

尝试在vscode中删除颤振调试工具栏