Listview filter search in Flutter

2020-05-16 03:35发布

  var userDetails = {};
  var i;
  List returnTicketDetails = [] ;

  body: new Column(
        children: <Widget>[
          new Container(
            color: Theme.of(context).primaryColor,
            child: new Padding(
              padding: const EdgeInsets.all(8.0),
              child: new Card(
                child: new ListTile(
                  leading: new Icon(Icons.search),
                  title: new TextField(
                    controller: controller,
                    decoration: new InputDecoration(
                        hintText: 'Search', border: InputBorder.none),
                   // onChanged: onSearchTextChanged,
                  ),
                  trailing: new IconButton(icon: new Icon(Icons.cancel), onPressed: () {
                    controller.clear();
                   // onSearchTextChanged('');
                  },),
                ),
          new Expanded(
            child: userDetails.length != 0 || controller.text.isNotEmpty
                ? new ListView.builder(
               itemCount: userDetails.length,
              itemBuilder: (context, i) {
                return new Card(

                  child: new Column
                    (mainAxisSize: MainAxisSize.min, children:
                    <Widget>[
                    new Row(children: <Widget>[
                    new Container(
                    width: 80.0,
                    height: 80.0,
                    decoration: new BoxDecoration(
                    shape: BoxShape.circle,
                    image: new DecorationImage(
                    fit: BoxFit.fill,
                    image: new NetworkImage(
                    "https:..")
                )
                )),
                    new Text(userDetails[returnTicketDetails[i]["user_id"]]["first_name"]
                    ),),
                  ,),
                    new Text(userDetails[returnTicketDetails[i]["user_id"]]["last_name"]),
                );
                },
            )
                : new ListView.builder(
               itemCount: userDetails.length,
              itemBuilder: (context, i) {
                return new Card(
                  child: new ListTile(
                    //title: new Text(userDetails[returnTicketDetails[i]["user_id"]]["first_name"]),
                  ),
                  margin: const EdgeInsets.all(0.0),
                );
    );
      }
 _getTicketDetails() async {
     final response = await http.get(
         "https..", headers: {
       HttpHeaders.AUTHORIZATION: access_token
     });
      returnTicketDetails = json.decode(response.body);
     for ( i = 0; i < (returnTicketDetails?.length ?? 0); i++) {
       final ticketresponse = await http.get(
           "https...", headers: {
         HttpHeaders.AUTHORIZATION:
         access_token
       });
       userDetails[returnTicketDetails[i]["user_id"]] =
           json.decode(ticketresponse.body);
   }
   }

This is how my interface looks like right now

I was wondering how to make the search function works according to the index of my ListView? So for instance if I input a z according to my case, I should not display anything in the List. I have also updated and posted the function _getTicketDeatils() here.

标签: dart flutter
7条回答
疯言疯语
2楼-- · 2020-05-16 04:04

With reference to Vinoth Kumar's answer, it's good to note that .contains() is case-sensitive. So, to exhaust all matches, you could transform the strings to lowercase:

_userDetails.forEach((userDetail) {
    if (userDetail.firstName.toLowerCase().contains(text.toLowerCase()) || userDetail.lastName.toLowerCase().contains(text.toLowerCase()))
      _searchResult.add(userDetail);
 });

Works perfectly for me.

查看更多
Animai°情兽
3楼-- · 2020-05-16 04:05

I'm learning Flutter and was looking for a searchable list which @Vinoth Kumar example does perfectly.

I've split the code into different files and reduced the HomePage body into several methods to make it more maintainable/readable for myself and I figured it would be worth sharing.

main.dart

import 'package:flutter/material.dart';
import 'homepage.dart';

void main() => runApp(new MaterialApp(
      home: new HomePage(),
      debugShowCheckedModeBanner: false,
    ));

homepage.dart

import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'userDetails.dart';

class HomePage extends StatefulWidget {
  HomePage({Key key}) : super(key: key);

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

class _HomePageState extends State<HomePage> {
  List<UserDetails> _searchResult = [];
  List<UserDetails> _userDetails = [];
  TextEditingController controller = new TextEditingController();

  // Get json result and convert it to model. Then add
  Future<Null> getUserDetails() async {
    final response = await http.get(url);
    final responseJson = json.decode(response.body);

    setState(() {
      for (Map user in responseJson) {
        _userDetails.add(UserDetails.fromJson(user));
      }
    });
  }

  @override
  void initState() {
    super.initState();

    getUserDetails();
  }

  Widget _buildUsersList() {
    return new ListView.builder(
      itemCount: _userDetails.length,
      itemBuilder: (context, index) {
        return new Card(
          child: new ListTile(
            leading: new CircleAvatar(
              backgroundImage: new NetworkImage(
                _userDetails[index].profileUrl,
              ),
            ),
            title: new Text(_userDetails[index].firstName +
                ' ' +
                _userDetails[index].lastName),
          ),
          margin: const EdgeInsets.all(0.0),
        );
      },
    );
  }

  Widget _buildSearchResults() {
    return new ListView.builder(
      itemCount: _searchResult.length,
      itemBuilder: (context, i) {
        return new Card(
          child: new ListTile(
            leading: new CircleAvatar(
              backgroundImage: new NetworkImage(
                _searchResult[i].profileUrl,
              ),
            ),
            title: new Text(
                _searchResult[i].firstName + ' ' +_searchResult[i].lastName),
          ),
          margin: const EdgeInsets.all(0.0),
        );
      },
    );
  }

  Widget _buildSearchBox() {
    return new Padding(
      padding: const EdgeInsets.all(8.0),
      child: new Card(
        child: new ListTile(
          leading: new Icon(Icons.search),
          title: new TextField(
            controller: controller,
            decoration: new InputDecoration(
                hintText: 'Search', border: InputBorder.none),
            onChanged: onSearchTextChanged,
          ),
          trailing: new IconButton(
            icon: new Icon(Icons.cancel),
            onPressed: () {
              controller.clear();
              onSearchTextChanged('');
            },
          ),
        ),
      ),
    );
  }

  Widget _buildBody() {
    return new Column(
      children: <Widget>[
        new Container(
            color: Theme.of(context).primaryColor, child: _buildSearchBox()),
        new Expanded(
            child: _searchResult.length != 0 || controller.text.isNotEmpty
                ? _buildSearchResults()
                : _buildUsersList()),
      ],
    );
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Home'),
        elevation: 0.0,
      ),
      body: _buildBody(),
      resizeToAvoidBottomPadding: true,
    );
  }

  onSearchTextChanged(String text) async {
    _searchResult.clear();
    if (text.isEmpty) {
      setState(() {});
      return;
    }

    _userDetails.forEach((userDetail) {
      if (userDetail.firstName.contains(text) ||
          userDetail.lastName.contains(text)) _searchResult.add(userDetail);
    });

    setState(() {});
  }
}

userDetails.dart

import 'package:flutter/material.dart';

final String url = 'https://jsonplaceholder.typicode.com/users';
class UserDetails {
  final int id;
  final String firstName, lastName, profileUrl;

  UserDetails({this.id, this.firstName, this.lastName, this.profileUrl = 'https://i.amz.mshcdn.com/3NbrfEiECotKyhcUhgPJHbrL7zM=/950x534/filters:quality(90)/2014%2F06%2F02%2Fc0%2Fzuckheadsho.a33d0.jpg'});

  factory UserDetails.fromJson(Map<String, dynamic> json) {
    return new UserDetails(
      id: json['id'],
      firstName: json['name'],
      lastName: json['username'],
    );
  }
}
查看更多
迷人小祖宗
4楼-- · 2020-05-16 04:06

In Flutter, we have to manage with a custom filter widget and we have to compare tow different objects lists. Such as

if (country.name.toLowerCase().contains(searchQuery) ||
          country.name.contains(searchQuery)) {
        filteredRecored.add(country);
      }

I found example here

查看更多
趁早两清
5楼-- · 2020-05-16 04:08

Here is another method to filter the list

_searchResult = _userDetails.where(
                    (userDetail) => (userDetail.firstName.contains(text) || userDetail.lastName.contains(text))
                );
查看更多
够拽才男人
6楼-- · 2020-05-16 04:14

add this in your pub.yaml file: flutter_slidable:^0.5.4

    import 'package:flutter/material.dart';
    import 'produit_bloc.dart';
    import 'produit_service.dart';
    import 'package:flutter_slidable/flutter_slidable.dart';

    class CRUDListView extends StatefulWidget {
      @override
      _CRUDListViewState createState() => _CRUDListViewState();
    }

    class _CRUDListViewState extends State<CRUDListView> {
      List<Produit> _produits;
      List<Produit> _searchProduct;
      TextEditingController controller = new TextEditingController();

      @override
      void initState() {
        super.initState();
        _produits = [];
        _searchProduct = [];
        _getEmployees();
      }

      _getEmployees() {
        ProduitService.getProduits().then((produits) {
          setState(() {
            _produits = produits;
          });
          print("Length ${produits.length} ");
        });
      }

      @override
      Widget build(BuildContext context) {
        return Scaffold(
          backgroundColor: Colors.grey,
          appBar: new AppBar(
            title: new Text('SEARCH ON LISTVIEW'),
            elevation: 0.0,
          ),
          body: new Column(
            children: <Widget>[
              new Container(
                color: Theme.of(context).primaryColor,
                child: new Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: new Card(
                    child: new ListTile(
                      leading: new Icon(Icons.search),
                      title: new TextField(
                        controller: controller,
                        decoration: new InputDecoration(
                            hintText: 'Search', border: InputBorder.none),
                        onChanged: onSearchTextChanged,
                      ),
                      trailing: new IconButton(
                        icon: new Icon(Icons.cancel),
                        onPressed: () {
                          controller.clear();
                          onSearchTextChanged('');
                        },
                      ),
                    ),
                  ),
                ),
              ),
              new Expanded(
                child: _searchProduct.length != 0 || controller.text.isNotEmpty
                    ? new ListView.builder(
                        itemCount: _searchProduct.length,
                        itemBuilder: (context, i) {
                          return new Slidable(
                            actionPane: SlidableDrawerActionPane(),
                            actionExtentRatio: 0.25,
                            child: Container(
                              color: Colors.white,
                              child: ListTile(
                                leading: Text(('${_searchProduct[i].id}')),
                                title: Text(('${_searchProduct[i].article}')),
                                trailing: Text(('${_searchProduct[i].prixu}')),
                              ),
                            ),
                            actions: <Widget>[
                              IconSlideAction(
                                caption: 'Archive',
                                color: Colors.blue,
                                icon: Icons.archive,
                                onTap: () {
                                  print('archive');
                                },
                              ),
                              IconSlideAction(
                                caption: 'Share',
                                color: Colors.indigo,
                                icon: Icons.share,
                                onTap: () {
                                  print('share');
                                },
                              ),
                            ],
                            secondaryActions: <Widget>[
                              IconSlideAction(
                                caption: 'More',
                                color: Colors.black45,
                                icon: Icons.more_horiz,
                                onTap: () {
                                  print('more');
                                },
                              ),
                              IconSlideAction(
                                caption: 'Delete',
                                color: Colors.red,
                                icon: Icons.delete,
                                onTap: () {
                                  print('delete');
                                },
                              ),
                            ],
                          );
                        },
                      )
                    : new ListView.builder(
                        itemCount: _produits.length,
                        itemBuilder: (context, index) {
                          return new Slidable(
                            actionPane: SlidableDrawerActionPane(),
                            actionExtentRatio: 0.25,
                            child: Container(
                              color: Colors.white,
                              child: ListTile(
                                leading: Text(('${_produits[index].id}')),
                                title: Text(('${_produits[index].article}')),
                                trailing: Text(('${_produits[index].prixu}')),
                              ),
                            ),
                            actions: <Widget>[
                              IconSlideAction(
                                caption: 'Archive',
                                color: Colors.blue,
                                icon: Icons.archive,
                                onTap: () {
                                  print('archive');
                                },
                              ),
                              IconSlideAction(
                                caption: 'Share',
                                color: Colors.indigo,
                                icon: Icons.share,
                                onTap: () {
                                  print('share');
                                },
                              ),
                            ],
                            secondaryActions: <Widget>[
                              IconSlideAction(
                                caption: 'More',
                                color: Colors.black45,
                                icon: Icons.more_horiz,
                                onTap: () {
                                  print('more');
                                },
                              ),
                              IconSlideAction(
                                caption: 'Delete',
                                color: Colors.red,
                                icon: Icons.delete,
                                onTap: () {
                                  print('delete');
                                },
                              ),
                            ],
                          );
                        },
                      ),
              ),
            ],
          ),
        );
      }

      onSearchTextChanged(String text) async {
        _searchProduct.clear();
        if (text.isEmpty) {
          setState(() {});
          return;
        }

        _produits.forEach((produit) {
          if (produit.article.contains(text) || produit.prixu.contains(text))
            _searchProduct.add(produit);
        });

        setState(() {});
      }
    }
查看更多
虎瘦雄心在
7楼-- · 2020-05-16 04:20

I've replaced hardcoded model input with getting data from url as you needed.

import 'dart:async';

import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;

void main() => runApp(new MaterialApp(
  home: new HomePage(),
  debugShowCheckedModeBanner: false,
));

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => new _HomePageState();
}

class _HomePageState extends State<HomePage> {
  TextEditingController controller = new TextEditingController();

  // Get json result and convert it to model. Then add
  Future<Null> getUserDetails() async {
    final response = await http.get(url);
    final responseJson = json.decode(response.body);

    setState(() {
      for (Map user in responseJson) {
        _userDetails.add(UserDetails.fromJson(user));
      }
    });
  }

  @override
  void initState() {
    super.initState();

    getUserDetails();
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Home'),
        elevation: 0.0,
      ),
      body: new Column(
        children: <Widget>[
          new Container(
            color: Theme.of(context).primaryColor,
            child: new Padding(
              padding: const EdgeInsets.all(8.0),
              child: new Card(
                child: new ListTile(
                  leading: new Icon(Icons.search),
                  title: new TextField(
                    controller: controller,
                    decoration: new InputDecoration(
                        hintText: 'Search', border: InputBorder.none),
                    onChanged: onSearchTextChanged,
                  ),
                  trailing: new IconButton(icon: new Icon(Icons.cancel), onPressed: () {
                    controller.clear();
                    onSearchTextChanged('');
                  },),
                ),
              ),
            ),
          ),
          new Expanded(
            child: _searchResult.length != 0 || controller.text.isNotEmpty
                ? new ListView.builder(
              itemCount: _searchResult.length,
              itemBuilder: (context, i) {
                return new Card(
                  child: new ListTile(
                    leading: new CircleAvatar(backgroundImage: new NetworkImage(_searchResult[i].profileUrl,),),
                    title: new Text(_searchResult[i].firstName + ' ' + _searchResult[i].lastName),
                  ),
                  margin: const EdgeInsets.all(0.0),
                );
              },
            )
                : new ListView.builder(
              itemCount: _userDetails.length,
              itemBuilder: (context, index) {
                return new Card(
                  child: new ListTile(
                    leading: new CircleAvatar(backgroundImage: new NetworkImage(_userDetails[index].profileUrl,),),
                    title: new Text(_userDetails[index].firstName + ' ' + _userDetails[index].lastName),
                  ),
                  margin: const EdgeInsets.all(0.0),
                );
              },
            ),
          ),
        ],
      ),
    );
  }

  onSearchTextChanged(String text) async {
    _searchResult.clear();
    if (text.isEmpty) {
      setState(() {});
      return;
    }

    _userDetails.forEach((userDetail) {
      if (userDetail.firstName.contains(text) || userDetail.lastName.contains(text))
        _searchResult.add(userDetail);
    });

    setState(() {});
  }
}

List<UserDetails> _searchResult = [];

List<UserDetails> _userDetails = [];

final String url = 'https://jsonplaceholder.typicode.com/users';
class UserDetails {
  final int id;
  final String firstName, lastName, profileUrl;

  UserDetails({this.id, this.firstName, this.lastName, this.profileUrl = 'https://i.amz.mshcdn.com/3NbrfEiECotKyhcUhgPJHbrL7zM=/950x534/filters:quality(90)/2014%2F06%2F02%2Fc0%2Fzuckheadsho.a33d0.jpg'});

  factory UserDetails.fromJson(Map<String, dynamic> json) {
    return new UserDetails(
      id: json['id'],
      firstName: json['name'],
      lastName: json['username'],
    );
  }
}
查看更多
登录 后发表回答