如何在Flutter应用中实施搜索

时间:2019-09-03 03:09:23

标签: search flutter

我正尝试向此flutter应用程序添加搜索功能,因为从中提取数据的json文件具有7000个结果。

主要是我想搜索“ ctry”和“ peopnameincountry”。这是从https://www.youtube.com/watch?v=EwHMSxSWIvQ

中删除的

..按原样..在获取json列表时效果很好,而点击以显示详细信息页面也很好。

我只需要在主页上执行搜索,因此不必滚动浏览成千上万的结果。

感谢任何帮助..谢谢大家。

if

4 个答案:

答案 0 :(得分:1)

Try adding these function in your code:
import 'package:flutter/material.dart';
import 'dart:core';

class HomeScreen1 extends StatefulWidget {
  @override
  HomeScreenState createState() => HomeScreenState();
}

class HomeScreenState extends State<HomeScreen1> {
  var searchController = new TextEditingController();
  String search;
  List<String> _filterList;
  String _query = "";
  bool _firstSearch = true;

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

  HomeScreenState() {
    searchController.addListener(() {
      if (searchController.text.isEmpty) {
        setState(() {
          _firstSearch = true;
          _query = "";
        });
      } else {
        setState(() {
          _firstSearch = false;
          _query = searchController.text;
        });
      }
    });
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: new Container(
        margin: EdgeInsets.only(left: 10.0, right: 10.0, top: 10.0),
        child: new Column(
          children: <Widget>[
            _createSearchView(),
            new Expanded(
              child: _firstSearch ? _createListView() : _performSearch(),
            ),
          ],
        ),
      ),
    );
  }

  Widget _createSearchView() {
    return new Container(
      decoration: BoxDecoration(border: Border.all(width: 1.0)),
      child: new TextField(
        controller: searchController,
        decoration: InputDecoration(
          icon: Icon(Icons.search),
          hintText: "Search",
          hintStyle: new TextStyle(color: Colors.grey[300]),
        ),
        //textAlign: TextAlign.center,
      ),
    );
  }

  Widget _createListView() {
    return FutureBuilder(
          future: _getUsers(),
          builder: (BuildContext context, AsyncSnapshot snapshot){
            print(snapshot.data);
            if(snapshot.data == null){
              return Container(
                  child: Center(
                      child: Text("Loading...")
                  )
              );
            } else {
              return ListView.builder(
                itemCount: snapshot.data.length,
                itemBuilder: (BuildContext context, int index) {
                  return ListTile(
                    leading: Icon(Icons.arrow_forward_ios),
//                    leading: CircleAvatar(
//                      backgroundImage: NetworkImage(
//                          snapshot.data[index].picture
//                      ),
//                    ),
                    title: Text(snapshot.data[index].peopnameincountry),
                    subtitle: Text(snapshot.data[index].ctry),
                    onTap: (){

                      Navigator.push(context,
                          new MaterialPageRoute(builder: (context) => DetailPage(snapshot.data[index]))
                      );

                    },
                  );
                },
              );
            }
          },
        ),
  }


  Widget _performSearch() {
    return FutureBuilder<List>(builder: (context, snapshot) {
      _filterList = new List<String>();
      for (int i = 0; i < snapshot.data.length; i++) {
        var item = snapshot.data[i];
        if ((item.toString().toLowerCase()).contains(_query.toLowerCase())) {

          _filterList.add(item.toString());
        }
      }
      return _createFilteredListView();
    });
  }

  Widget _createFilteredListView() {
    return ListView.builder(
        itemCount: _filterList.length,
        itemBuilder: (BuildContext context, int index) {
          return new Card(
            color: Colors.white,
            elevation: 5.0,
            child: new Container(
              margin: EdgeInsets.all(15.0),
              child: new Text("${_filterList[index]}"),
            ),
          );
        });
  }
}

答案 1 :(得分:0)

FutureBuilder小部件的概念将在收到后立即构建,但与此同时,快照完全不包含任何数据。因此,当您打电话时:

for (int i = 0; i < snapshot.data.length; i++) {

由于尚未收到数据,因此至少在开始时,您正在length上调用null

解决方案是创建一个开关,并在状态完成时调用`snapshot.data:

    switch (snapshot.connectionState) {
      case ConnectionState.none:
        return DefaultWidget();         // For instance a CircularProgress

      case ConnectionState.active:
        return DefaultWidget();         // For instance a CircularProgress

      case ConnectionState.waiting:
        return DefaultWidget();         // For instance a CircularProgress

      case ConnectionState.done:

        if (snapshot.hasError)
          return ErrorWidget('Error: ${snapshot.error}'); //For example a Text Widget 

         // Your code here:
        _filterList = new List<String>();
      for (int i = 0; i < snapshot.data.length; i++) {
        var item = snapshot.data[i];
        if ((item.toString().toLowerCase()).contains(_query.toLowerCase())) {

          _filterList.add(item.toString());
        }
      }
      return _createFilteredListView();
    }
    return null; // unreachable

有关此here

的更多信息

答案 2 :(得分:-1)

首先感谢您抽出宝贵的时间。 我遇到错误:

Another exception was thrown: NoSuchMethodError: The getter 'length' was called on null.

我认为是_performSearch窗口小部件。请查看下面的完整代码,让我知道可以解决的问题。谢谢!!!

除我尝试进行搜索时,其他所有内容都可以正常工作。

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


class IslandWaves extends StatefulWidget {
  @override
  HomeScreenState createState() => HomeScreenState();
}

class HomeScreenState extends State<IslandWaves> {

  var searchController = new TextEditingController();
  String search;
  List<String> _filterList;
  String _query = "";
  bool _firstSearch = true;

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

  HomeScreenState() {
    searchController.addListener(() {
      if (searchController.text.isEmpty) {
        setState(() {
          _firstSearch = true;
          _query = "";
        });
      } else {
        setState(() {
          _firstSearch = false;
          _query = searchController.text;
        });
      }
    });
  }

  Future<List<User>> _getUsers() async {

    var data = await http.get("https://cmfiflutterapp.s3-ap-southeast-2.amazonaws.com/UnreachedPeoplesGroup.json");

    var jsonData = json.decode(data.body);

    List<User> users = [];
    for(var u in jsonData){

      User user = User(u["ctry"], u["peopnameincountry"], u["population"], u["primarylanguagename"], u["biblestatus"],  u["primaryreligion"],  u["continent"]);

      users.add(user);

    }

    print(users.length);

    return users;

  }



  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Unreached'),
      ),
      body: new Container(
        margin: EdgeInsets.only(left: 10.0, right: 10.0, top: 10.0),
        child: new Column(
          children: <Widget>[
            _createSearchView(),
            new Expanded(
              child: _firstSearch ? _createListView() : _performSearch(),
            ),
          ],
        ),
      ),
    );
  }

  Widget _createSearchView() {
    return new Container(
      decoration: BoxDecoration(border: Border.all(width: 1.0)),
      child: new TextField(
        controller: searchController,
        decoration: InputDecoration(
          icon: Icon(Icons.search),
          hintText: "Search",
          hintStyle: new TextStyle(color: Colors.grey[300]),
        ),
        //textAlign: TextAlign.center,
      ),
    );
  }

  Widget _createListView() {
    return FutureBuilder(
      future: _getUsers(),
      builder: (BuildContext context, AsyncSnapshot snapshot){
        print(snapshot.data);
        if(snapshot.data == null){
          return Container(
              child: Center(
                  child: Text("Loading...")
              )
          );
        } else {
          return ListView.builder(
            itemCount: snapshot.data.length,
            itemBuilder: (BuildContext context, int index) {
              return ListTile(
                leading: Icon(Icons.arrow_forward_ios),
                title: Text(snapshot.data[index].peopnameincountry),
                subtitle: Text(snapshot.data[index].ctry),
                onTap: (){

                  Navigator.push(context,
                      new MaterialPageRoute(builder: (context) => DetailPage(snapshot.data[index]))
                  );
                },
              );
            },
          );
        }
      },
    );
  }

  Widget _performSearch() {
    return FutureBuilder<List>(builder: (context, snapshot) {
      _filterList = new List<String>();
      for (int i = 0; i < snapshot.data.length; i++) {
        var item = snapshot.data[i];
        if ((item.toString().toLowerCase()).contains(_query.toLowerCase())) {

          _filterList.add(item.toString());
        }
      }
      return _createFilteredListView();
    });
  }

  Widget _createFilteredListView() {
    return ListView.builder(
        itemCount: _filterList.length,
        itemBuilder: (BuildContext context, int index) {
          return new Card(
            color: Colors.white,
            elevation: 5.0,
            child: new Container(
              margin: EdgeInsets.all(15.0),
              child: new Text("${_filterList[index]}"),
            ),
          );
        });
  }
}


答案 3 :(得分:-1)

我道歉的家伙……我最终采用了稍微不同的方法,我认为响应速度比FutureBuilder方法稍快。也许这只是我的互联网。不确定。

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

class IslandWaves extends StatefulWidget {
  @override
  HomeScreenState createState() => HomeScreenState();
}

class HomeScreenState extends State<IslandWaves> {
  List<User> _list = [];
  List<User> _search = [];
  var loading = false;
  Future<Null> fetchData() async {
    setState(() {
      loading = true;
    });
    _list.clear();
    final response = await http.get(
        "https://cmfiflutterapp.s3-ap-southeast-2.amazonaws.com/UnreachedPeoplesGroup.json");
    if (response.statusCode == 200) {
      final data = jsonDecode(response.body);
      setState(() {
        for (Map i in data) {
          _list.add(User.formJson(i));
          loading = false;
        }
      });
    }
  }

  TextEditingController controller = new TextEditingController();

  onSearch(String text) async {
    _search.clear();
    if (text.isEmpty) {
      setState(() {});
      return;
    }

    _list.forEach((f) {
      if (f.ctry.contains(text) ||
          f.peopnameincountry.toString().contains(text)) _search.add(f);
    });

    setState(() {});
  }

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    fetchData();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Container(
        child: Column(
          children: <Widget>[
            Container(
              padding: EdgeInsets.all(10.0),
              color: Colors.blue,
              child: Card(
                child: ListTile(
                  leading: Icon(Icons.search),
                  title: TextField(
                    controller: controller,
                    onChanged: onSearch,
                    decoration: InputDecoration(
                        hintText: "Search", border: InputBorder.none),
                  ),
                  trailing: IconButton(
                    onPressed: () {
                      controller.clear();
                      onSearch('');
                    },
                    icon: Icon(Icons.cancel),
                  ),
                ),
              ),
            ),
            loading
                ? Center(
                    heightFactor: 20.0,
                    child: FadingText('Loading...'),
                  )
                : Expanded(
                    child: _search.length != 0 || controller.text.isNotEmpty
                        ? ListView.builder(
                            itemCount: _search.length,
                            itemBuilder: (context, i) {
                              final b = _search[i];
                              return GestureDetector(
                                onTap: () {
                                  Navigator.push(
                                      context,
                                      new MaterialPageRoute(
                                          builder: (context) =>
                                              DetailPage(_search[i])));
                                  debugPrint('TopNav');
                                },
                                child: Container(
                                    padding: EdgeInsets.all(10.0),
                                    child: Column(
                                      crossAxisAlignment:
                                          CrossAxisAlignment.start,
                                      children: <Widget>[
                                        Text(
                                          b.ctry,
                                          style: TextStyle(
                                              fontWeight: FontWeight.bold,
                                              fontSize: 18.0),
                                        ),
                                        SizedBox(
                                          height: 4.0,
                                        ),
                                        Text(b.peopnameincountry),
                                      ],
                                    )),
                              );
                            },
                          )
                        : ListView.builder(
                            itemCount: _list.length,
                            itemBuilder: (context, i) {
                              final a = _list[i];
                              return GestureDetector(
                                onTap: () {
                                  Navigator.push(
                                      context,
                                      new MaterialPageRoute(
                                          builder: (context) =>
                                              DetailPage(_list[i])));
                                  debugPrint('BottomNav');
                                },
                                child: Container(
                                    padding: EdgeInsets.all(10.0),
                                    child: Column(
                                      crossAxisAlignment:
                                          CrossAxisAlignment.start,
                                      children: <Widget>[
                                        Text(
                                          a.ctry,
                                          style: TextStyle(
                                              fontWeight: FontWeight.bold,
                                              fontSize: 18.0),
                                        ),
                                        SizedBox(
                                          height: 4.0,
                                        ),
                                        Text(a.peopnameincountry),
                                      ],
                                  )
                                ),
                            );
                        },
                   ),
              ),
          ],
        ),
      ),
    );
  }
}

class DetailPage extends StatelessWidget{....etc.}