【问题标题】:Searchbar getting Text but not filtering List搜索栏获取文本但不过滤列表
【发布时间】:2020-04-30 06:53:37
【问题描述】:

如标题所述,我有一个要过滤的 Listview。我查找了无数的示例和代码 sn-ps,但我仍然没有找到我必须放置的地方

list = list.where((u)=>(u.name.toLowerCase().contains(_searchText.toLowerCase())
            .toList()));

过滤列表。

我假设我必须在构建列表的方式上进行一些更改。 Textfield 已经可以正常工作了,_searchText 始终是 Textfield 所说的内容。

我的代码:

import 'dart:developer';

import 'package:flutter/material.dart';
import 'package:flutter_ac/collectible/collectible_details.dart';
import 'package:flutter_ac/nooklets/nook_scaffold.dart';
import 'package:flutter_ac/nooklets/nook_search.dart';
import 'package:flutter_ac/nooklets/nook_sheet.dart';
import 'package:flutter_ac/settings.dart';
import 'package:provider/provider.dart';

import 'collectible.dart';

final TextEditingController _filter = new TextEditingController();

class CollectibleList<C extends Collectible> extends StatefulWidget {
  final List<C> collectibles;
  final String title;
  

  CollectibleList(
    this.collectibles,
    {
      this.title,
    }

  );

  @override
  State<StatefulWidget> createState() => _CollectibleList<C>();
}

class _CollectibleList<C extends Collectible> extends State<CollectibleList<C>> {
  Widget _appBarTitle;
  bool _isSearching;
  String _searchText = "";
  List _collectibles = new List(); 
  List _filteredCollectibles = new List(); 
  Icon _searchIcon = new Icon(Icons.search); 
  final key = new GlobalKey<ScaffoldState>();
  var list;

  _CollectibleList(){
      _filter.addListener(() {

      if (_filter.text.isEmpty) {

        setState(() {

          _searchText = "";
          _isSearching = false;
         list = list.where((u)=>(u.name.toLowerCase().contains(_searchText.toLowerCase())
            .toList()));

        });

      } else {

        setState(() {

          _searchText = _filter.text;

          log(_searchText);

        });

      }

    });
  }
  void _openDetails(Collectible collectible) {
    var locale = Localizations.localeOf(context);

    log("Opening collectible details for ${collectible.name(locale)}");

    Navigator.push(
      context,
      MaterialPageRoute(builder: (context) => CollectibleDetails(collectible)),
    );
    
  }

  @protected
  @override
  void initState() {
    _appBarTitle = new Text(widget.title ?? "");
    super.initState();
      _isSearching = false;
  }

  @override
  Widget build(BuildContext context) {
    var locale = Localizations.localeOf(context);
    var collectibles = widget.collectibles ?? [];

    var list = ListView.separated(
      separatorBuilder: (context, index) => Divider(
        height: 1,
        thickness: 1,
      ),
      itemCount: collectibles.length,
      itemBuilder: (context, index) {
        Collectible collectible = collectibles[index];

        return Consumer<Settings>(
          builder: (context, settings, child) {
            var titleStyle = !collectible.isObtained(settings) ?
              null :
              TextStyle(
                color: Colors.lightGreen,
              );

            return Material(
              color: Colors.transparent,
              child: ListTile(
                leading: Hero(
                  tag: collectible.heroTag,
                  child: Container(
                    child: Image(image: collectible.icon),
                    width: 50,
                    height: 50,
                    alignment: Alignment.center,
                  ),
                ),
                title: Text("${collectible.name(locale)}", style: titleStyle),
                subtitle: collectible.listSubtitle(context),
                trailing: collectible.listTrailing(context),
                onTap: () => _openDetails(collectible),
                onLongPress: () {
                  var isObtained = collectible.isObtained(settings);
                  collectible.setObtained(settings, !isObtained);
                },
              ),
            );
          },
        );
      }
    );

    return Scaffold(
      appBar: AppBar(
        title: _appBarTitle,
        centerTitle: true,
        backgroundColor: Color.fromRGBO(95, 199, 188, 1.0),
        actions: <Widget>[
          IconButton(
            icon: _searchIcon,
            onPressed: () {
              log("Searchbutton pressed");
              _searchPressed();
              //showSearch(context: context, delegate: Datasearch());
              }
          ),
          IconButton(
            icon: const Icon(Icons.filter_list)
          )
        ],
      ),
      body: NookScaffold(
        body: NookSheet(
            child: 
              Column(children:<Widget>[
                DropdownButton(onChanged: (String newValue) {
                  setState(() {
                    String dropdownValue = newValue;
                  });       
                }
                ),
                
                Expanded(child: list)
              ],),
          ),
        titleMargin: 0,
      )
    );
  }


  void _searchPressed() {
    setState(() 
      {
        if (this._searchIcon.icon == Icons.search) {
          this._searchIcon = new Icon(Icons.close);
          this._appBarTitle = new TextField(
            controller: _filter,
            decoration: new InputDecoration(
              prefixIcon: new Icon(Icons.search),
              hintText: 'Search...',
            ),
            
          );
          _handleSearchStart();
        } else {
          this._searchIcon = new Icon(Icons.search);
          this._appBarTitle = new Text(widget.title ?? "");
          _filteredCollectibles = _collectibles;
          _filter.clear();
        }
      }
    );
  }

    void _handleSearchStart(ListView list) {
    setState(() {
      _isSearching = true;
    });
  }
  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();
    }
  }


  }

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

  
}

【问题讨论】:

  • 您每次都在使用小部件的收藏品填充列表视图。 var collectibles = widget.collectibles ?? [];。将 widget.collectible 分配给某个状态变量并过滤该变量。并将该变量提供给列表视图。
  • 如果我写filteredCollectibles = collectibles.where((u)=&gt;(u.name.toLowerCase().contains(_searchText.toLowerCase()) .toList()));,我会得到一个错误:方法'toLowerCase'没有为'Function'类型定义。尝试将名称更正为现有方法的名称,或定义名为“toLowerCase”的方法。dart(undefined_method)

标签: listview flutter dart


【解决方案1】:

您似乎正在尝试为您的文本字段实现“键入时搜索”功能。

有两种方法(可能更多)来实现这一点。

1。手动方式:

您可以使用流来侦听用户输入的内容,并根据输入的数据过滤您提供给列表项的数据。

更好的解释:当用户键入时,对于他/她击中的每个字符,您都会将数据发送到您的流中,而从另一端,您会继续收听正在馈送到流中的内容。用户键入“A”,您将“A”提供给您的流并从另一端获得相同的内容,并使用“A”过滤开始/结束的所有内容(或任何您需要的......)。这适用于用户输入的每个字符。

代码示例:(假设您的 UI 和数据函数在不同的文件中)

这就是你的 BLOC 类的样子,它有一个 StreamController,它的工作只是监听数据并将其传递到你需要的地方。

class Bloc{
  final _textFieldController = StreamController<String>();

  //Use this to get data out of the stream
  Stream<String> get enteredCharacter => _textFieldController.stream;

  //returns functions to change data
  Function(String) get addText => _textFieldController.sink.add;

  dispose() {
    _textFieldController.close();
  }
}
//Here we are using a single instance of the bloc class, Which you can access from anywhere.
final bloc = Bloc();

现在,如何使用它?

在您的数据函数所在的文件中,更重要的是,正在馈送到列表视图的数据所在的位置,您需要按如下方式监听流中的内容:

var enteredCharacter = "";
bloc.enteredCharacter.listen((data) {
  print("This is the character entered by the user: $data");
  enteredCharacter = data;
  _filterData(); //This function will filter your data based on the characters that the user hits.
});

简单或预建方式:

使用一个名为 autocomplete_textfield 的插件,它易于使用并且几乎可以完成这项工作。

Click here for plugin

【讨论】:

  • 您简单的预构建方式描述让我发笑。我将尝试同时使用两者并继续使用更合适的方法
  • 我明白你在写什么,但我找不到我必须放置你的代码的确切位置,因为你似乎使用了一些其他声明。我在 ``` var collectibles = widget.collectibles ?? 处为 Listview 创建数据[]; ``` 但我不知道我必须如何改变它。我仍然是飞镖的新手
  • 我已经获得了过滤列表所需的文本。但我无法真正获得过滤列表的正确部分
  • 好的,你是说流正在返回数据(用户输入的字符)?
  • print("这是用户输入的字符:$data");这是打印到控制台吗?
猜你喜欢
  • 2021-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-08
  • 1970-01-01
  • 2016-01-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多