Flutter - мгновенный фильтр (поиск) ListView с данными из SQFlite - PullRequest
0 голосов
/ 18 марта 2020

У меня есть Listview и Textfield, которые работают как панель поиска (я должен также отметить, что каждый из них принадлежит к другому классу) Я пытаюсь мгновенно отфильтровать представление списка как пользователь набирает

Я добился прогресса в правильном направлении, но проблема в том, что я ищу что-то похожее на этот пример mList.contains(userSearch)

То, что у меня сейчас нет Точно не соответствует требованию, он выполняет поиск, но только когда пользователь прекращает печатать, он не обнаруживает изменения в реальном времени в текстовом поле.

Получение данных из базы данных SQFlite:

//getting full list
Future<List<Word>> getAllWords() async {
    final db = await database;
    var response = await db.query(TABLE_WORDS);
    List<Word> list = response.map((c) => Word.fromMap(c)).toList();
    return list;
}

//getting search results
Future<List<Word>> searchResults(String userSearch) async {
    final db = await database;
    var response = await db.query(TABLE_WORDS, where: '$COL_ENGLISH_WORD = ? OR $COL_GERMAN_WORD = ?', whereArgs: [userSearch, userSearch]);
    List<Word> list = response.map((c) => Word.fromMap(c)).toList();
    return list;
}

Теперь страница, на которой я отображаю список и строку поиска:

String userSearchInput = "";
TextEditingController _searchInputController = TextEditingController();

class FullList extends StatefulWidget {
    @override
    _FullListState createState() => _FullListState();
} 

class _FullListState extends State<FullList> {
    @override
    void initState() {

    search(String userInput){
      setState(() {
        userInput = _searchInputController.text;
        if(userInput.isEmpty){
          return;
        }else{
          userSearchInput = userInput;
        }
      });
    }

    @override
    Widget build(BuildContext context) {
        return Scaffold(
            resizeToAvoidBottomInset: false,
            appBar: AppBar(
                primary: true,
                title: InkWell(
                  splashColor: gradientStart,
                  child: TextField(
                      autofocus: false,
                      enableInteractiveSelection: false,                     
                      controller: _searchInputController,
                      onChanged: search,
                      decoration: InputDecoration(hintText: "Search"),
                ),
             ),
          ),
          body: Container(
              height: MediaQuery.of(context).size.height,
              child: SafeArea(
                  child: ListPage(),
              ),
          ),
      );
   }
}

//The class that has the listview
class ListPage extends StatefulWidget {
    @override
   _ListPageState createState() => _ListPageState();
}

class _ListPageState extends State<ListPage> {
    DatabaseHelper databaseHelper;

    @override
    void initState() {
      databaseHelper = DatabaseHelper.databaseHelper;

      super.initState();
    }
    @override
    Widget build(BuildContext context) {

        return Container(
          child: FutureBuilder<List<Word>>(
            future: _searchInputController.text.isEmpty ? databaseHelper.getAllWords() : databaseHelper.searchResults(userSearchInput),
            builder: (BuildContext context, AsyncSnapshot<List<Word>> snapshot){
                if(snapshot.hasData){
                  return ListView.builder(
                      physics: const AlwaysScrollableScrollPhysics (),
                      shrinkWrap: true,
                      reverse: false,
                      controller: _scrollController,
                      itemCount: snapshot.data.length,
                      itemBuilder: (BuildContext context, int index) {
                          return GestureDetector(
                              onTap: () {/*take action*/},
                              child: AnimationConfiguration.staggeredList(
                              position: index,
                              duration: const Duration(milliseconds: 300),
                              child: SlideAnimation(
                                  verticalOffset: 50.0,
                                      child: FadeInAnimation(
                                      child: listChild(snapshot.data[index].eng, snapshot.data[index].ger),
                            ),
                          ),
                        ),
                      );
                    },
                  );
                }
                return Center(
                   child: CircularProgressIndicator()
                );
              }
           ),
        );
      }
}

Вопрос: Как я могу изменить это, чтобы иметь возможность мгновенно фильтровать список при вводе пользователем?

1 Ответ

0 голосов
/ 18 марта 2020

Я думаю, что проблема в вашем initState (). Вы должны переместить его из initState. Кроме того, вы можете решить, как это; Сначала определите 2 List,

List<Word> list = List<Word>();
List<Word> filteredList = List<Word>();

Затем, когда вы получаете данные из снимка, присвойте полученный список списку, который вы определили. Вот так:

if(snapshot.hasData){

   if(!doItJustOnce){ //You should define a bool like (bool doItJustOnce = false;) on your state.
      list = snapshot.data;
      filteredList = list;
      doItJustOnce = !doItJustOnce; //this line helps to do just once.
   }

   return ListView.builder(
   ...

А затем добавьте свой список

itemCount: filteredList.length,

и вот это;

FadeInAnimation(
   child: listChild(filteredList[index].eng, filteredList[index].nor),
)

Наконец, вы должны сделать такую ​​пустоту, как эта;

 void _filterList(value) {
    setState(() {
      filteredList = list.where((text) => text.fileName.toLowerCase().contains(value.toLowerCase())).toList();
    });
  }

и добавьте onChanged вашего TextField;

onChanged: (value) {
    _filterList(value);
},

Если вы сбросите свой список, просто напишите эти строки;

setState(() {
    filteredList = list;
 });

Вы можете попробовать свои коды;

import 'package:flutter/material.dart';

class FullList extends StatefulWidget {
  @override
  _FullListState createState() => _FullListState();
}

class _FullListState extends State<FullList> {
  String userSearchInput = "";
  TextEditingController _searchInputController = TextEditingController();

  DatabaseHelper databaseHelper;
  List<Word> list = List<Word>();
  List<Word> filteredList = List<Word>();
  bool doItJustOnce = false;

  void _filterList(value) {
    setState(() {
      filteredList = list
          .where((text) => text.eng.toLowerCase().contains(value.toLowerCase()))
          .toList(); // I don't understand your Word list.
    });
  }

  @override
  void initState() {
    databaseHelper = DatabaseHelper.databaseHelper;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: false,
      appBar: AppBar(
        primary: true,
        title: InkWell(
          splashColor: gradientStart,
          child: TextField(
            autofocus: false,
            enableInteractiveSelection: false,
            controller: _searchInputController,
            onChanged: (value) {
              _filterList(value);
            },
            decoration: InputDecoration(hintText: "Search"),
          ),
        ),
      ),
      body: Container(
        height: MediaQuery.of(context).size.height,
        child: SafeArea(
          child: Container(
            child: FutureBuilder<List<Word>>(
                future: databaseHelper.getAllWords(),
                builder: (BuildContext context, AsyncSnapshot<List<Word>> snapshot) {
                  if (snapshot.hasData) {
                    if (!doItJustOnce) {
                      //You should define a bool like (bool doItJustOnce = false;) on your state.
                      list = snapshot.data;
                      filteredList = list;
                      doItJustOnce = !doItJustOnce; //this line helps to do just once.
                    }
                    return ListView.builder(
                      physics: const AlwaysScrollableScrollPhysics(),
                      shrinkWrap: true,
                      reverse: false,
                      controller: _scrollController,
                      itemCount: filteredList.length,
                      itemBuilder: (BuildContext context, int index) {
                        return GestureDetector(
                          onTap: () {
                            /*take action*/
                          },
                          child: AnimationConfiguration.staggeredList(
                            position: index,
                            duration: const Duration(milliseconds: 300),
                            child: SlideAnimation(
                              verticalOffset: 50.0,
                              child: FadeInAnimation(
                                child: listChild(filteredList[index].eng, filteredList[index].ger),
                              ),
                            ),
                          ),
                        );
                      },
                    );
                  }
                  return Center(child: CircularProgressIndicator());
                }),
          ),
        ),
      ),
    );
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...