使用提供程序和模型类搜索/过滤ListView [英] Search/filter ListView with Provider and model classes

查看:29
本文介绍了使用提供程序和模型类搜索/过滤ListView的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想通过在搜索字段中输入的文字来过滤列表视图.在线和此站点上有许多示例,但是所有示例都通过一个有状态的小部件进行了简化,并且/或者看起来有些混乱,也许不是构造事物的最佳方法.我有一个使用Provider的简单应用程序,一个模型类(Dog)和一个Dogs类,其中包含我正在使用的列表.

I want to filter a list view by text entered into a search field. Many examples online and on this site, but all over-simplified with everything in a single stateful widget and/or seem a bit messy and maybe not the best way to structure things. I have a simple app that uses Provider, a model class (Dog) and a Dogs class that has my list I'm working with.

目标:根据输入的文字过滤狗的列表.

Goal: Filter the list of dogs by text entered.

狗模型

class Dog {
  final String breed;
  final String name;
  final int age;

  Dog({this.breed, this.name, this.age});
}

狗班

import 'package:flutter/cupertino.dart';
import 'dart:collection';

import '../models/dog.dart';

class Dogs extends ChangeNotifier {
  final List<Dog> _myDogs = [
    Dog(name: 'Mackie', age: 8, breed: 'Rottweiler'),
    Dog(name: 'Riley', age: 8, breed: 'Rottweiler'),
    Dog(name: 'Tank', age: 7, breed: 'Mastiff'),
    Dog(name: 'Tanner', age: 7, breed: 'Mastiff'),
    Dog(name: 'Rocky', age: 10, breed: 'Rottweiler'),
    Dog(name: 'Angel', age: 11, breed: 'Poodle'),
    Dog(name: 'Roxie', age: 8, breed: 'St. Bernard'),
    Dog(name: 'Spud', age: 8, breed: 'St. Bernard'),
    Dog(name: 'Nick', age: 4, breed: 'Rottweiler'),
  ];

  UnmodifiableListView<Dog> get dogs => UnmodifiableListView(_myDogs);
}

Main with ListView

Main with ListView

import 'package:flutter/material.dart';

import 'package:provider/provider.dart';
import 'providers/dogs.dart';

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => Dogs(),
      child: MyApp(),
    ),
  );
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final _controller = TextEditingController();
  String _searchText;

  @override
  void initState() {
    _controller.addListener((){
      setState(() {
        _searchText = _controller.text;
      });
    },);
    super.initState();
  }

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Dogs',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Dogs'),
        ),
        body: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            TextField(
              controller: _controller,
              decoration: InputDecoration(
                hintText: "Search",
                prefixIcon: Icon(Icons.search),
                border: OutlineInputBorder(
                  borderRadius: BorderRadius.all(
                    Radius.circular(4.0),
                  ),
                ),
              ),
              onChanged: (value){
                //TODO when text is entered into search bar
              },
            ),
            Consumer<Dogs>(
              builder: (context, dogData, child) => Expanded(
                child: ListView.builder(
                    shrinkWrap: true,
                    itemCount: dogData.dogs.length,
                    itemBuilder: (context, index) => Card(
                          elevation: 3,
                          child: ListTile(
                            title: Text(dogData.dogs[index].name),
                          ),
                        )),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

经过几次迭代,从网上的经验中吸取了教训,到目前为止,我已经停止并清理了一切.

After several iterations, taking what I've learned from what I've found online, I've stopped and cleaned things up to this point.

我有显示狗的列表视图,并且有我的TextField 我正在使用有状态的小部件,因此可以将init用于TextController侦听器,并在完成后进行处置 我的文本控制器已与控制器一起设置,并且正在初始化一个变量,该变量会将搜索文本保存到controller.text 我相当确定我将需要使用TextField的onChanged来通过我的搜索工具使用该值(以某种方式)

I have my list view displaying dogs and have my TextField I am using a stateful widget so I can use init for the TextController listener and dispose to dispose of it when done My text controller is setup with the controller and I'm initializing a variable that will hold the search text to controller.text I am fairly certain I will need to use the onChanged of the TextField to use the value with my search facility (in some way)

当前,我的列表视图生成器正在基于dogData.dogs.length来获取列表,但是由于它只是从Dogs类中获取的内容,因此不包含用于过滤掉内容的逻辑.

Currently, my listview builder is getting the list based on dogData.dogs.length, but that includes no logic to filter things down since it's just a get from my Dogs class.

我可以轻松地在我的dos类中构建一个方法,该方法将使用.toLowerCase和.contains返回列表,该方法接受一些文本以用于使用过滤后的项目构建新列表,但是我在这里也做了很多工作因为我无法通过消费者将其绑定到我的dogData.

I can easily build a method in my does class that would return a list using .toLowerCase and .contains which accepts some text to use to build a new list with the filtered items, but I've spun out here a bunch too as I fail in getting it tied back to my dogData via the Consumer.

这是应用程序,移动应用程序,Web等中的常见任务,因此我必须相信有一种干净/优雅/正确(比其他方式更多)的方法来完成此任务.我想只是迷失在细节上.

This is such a common task in apps, mobile apps, web, etc., so I have to believe there is a clean/elegant/correct (more than other ways) method of accomplishing this task. Just getting lost in the details, I suppose.

任何帮助将不胜感激. 谢谢, 鲍勃

any help would be greatly appreciated. Thank you, Bob

推荐答案

您可以在
下复制粘贴运行完整代码 这个想法就像Todo App有3种不同的UnmodifiableListView

You can copy paste run full code below
The idea is like Todo App has 3 different UnmodifiableListView

UnmodifiableListView<Task> get allTasks, 
UnmodifiableListView<Task> get incompleteTasks
UnmodifiableListView<Task> get completedTasks

Todo的示例 https://dev .to/shakib609/create-to-todos-app-with-flutter-and-provider-jdh

您可以使用以下代码段根据搜索字符串返回所需的UnmodifiableListView,并在onChanged中调用provider changeSearchString
因此ListView之类的其他部分不必更改

You can use the following code snippet to return UnmodifiableListView you need based on search string and in onChanged call provider changeSearchString
so other part like ListView do not have to change

  String _searchString = "";

  UnmodifiableListView<Dog> get dogs => _searchString.isEmpty
      ? UnmodifiableListView(_myDogs)
      : UnmodifiableListView(
          _myDogs.where((dog) => dog.breed.contains(_searchString)));

  void changeSearchString(String searchString) {
    _searchString = searchString;
    print(_searchString);
    notifyListeners();
  }

  ...

  onChanged: (value) {
            Provider.of<Dogs>(context, listen: false)
                .changeSearchString(value);
          },

通过面包工作演示搜索狗

working demo search dog by bread

完整代码

import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'dart:collection';
import 'package:provider/provider.dart';

class Dogs extends ChangeNotifier {
  final List<Dog> _myDogs = [
    Dog(name: 'Mackie', age: 8, breed: 'Rottweiler'),
    Dog(name: 'Riley', age: 8, breed: 'Rottweiler'),
    Dog(name: 'Tank', age: 7, breed: 'Mastiff'),
    Dog(name: 'Tanner', age: 7, breed: 'Mastiff'),
    Dog(name: 'Rocky', age: 10, breed: 'Rottweiler'),
    Dog(name: 'Angel', age: 11, breed: 'Poodle'),
    Dog(name: 'Roxie', age: 8, breed: 'St. Bernard'),
    Dog(name: 'Spud', age: 8, breed: 'St. Bernard'),
    Dog(name: 'Nick', age: 4, breed: 'Rottweiler'),
  ];

  String _searchString = "";

  UnmodifiableListView<Dog> get dogs => _searchString.isEmpty
      ? UnmodifiableListView(_myDogs)
      : UnmodifiableListView(
          _myDogs.where((dog) => dog.breed.contains(_searchString)));

  void changeSearchString(String searchString) {
    _searchString = searchString;
    print(_searchString);
    notifyListeners();
  }
}

class Dog {
  final String breed;
  final String name;
  final int age;

  Dog({this.breed, this.name, this.age});
}

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => Dogs(),
      child: MyApp(),
    ),
  );
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final _controller = TextEditingController();
  String _searchText;

  @override
  void initState() {
    _controller.addListener(
      () {
        setState(() {
          _searchText = _controller.text;
        });
      },
    );
    super.initState();
  }

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Dogs',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Dogs'),
        ),
        body: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            TextField(
              controller: _controller,
              decoration: InputDecoration(
                hintText: "Search",
                prefixIcon: Icon(Icons.search),
                border: OutlineInputBorder(
                  borderRadius: BorderRadius.all(
                    Radius.circular(4.0),
                  ),
                ),
              ),
              onChanged: (value) {
                Provider.of<Dogs>(context, listen: false)
                    .changeSearchString(value);
              },
            ),
            Consumer<Dogs>(builder: (context, dogData, child) {
              print(dogData.dogs.toString());
              return Expanded(
                child: ListView.builder(
                    shrinkWrap: true,
                    itemCount: dogData.dogs.length,
                    itemBuilder: (context, index) => Card(
                          elevation: 3,
                          child: ListTile(
                            title: Text(dogData.dogs[index].name),
                          ),
                        )),
              );
            }),
          ],
        ),
      ),
    );
  }
}

这篇关于使用提供程序和模型类搜索/过滤ListView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆