在 Flutter 中使用文本形式搜索数据库 (SQLite)
Search database (SQLite) using a textform in Flutter
我正在尝试搜索我的 sqlite 数据库,现在它 returns 所有成员,即使在文本表单中输入了文本。我在 memberList 构造函数中有一个 ListView 构建器,它为每个成员创建卡片。我想要它做的是只显示与用户输入匹配的卡片。
即如果用户输入 J,它将仅显示名字或姓氏中带有字母 J 的成员。
我可以看到查询工作正常,因为我在 dbHelper class 中打印了计数,并且每次我更改文本表单的文本时它都会更新。我需要它做的基本上是刷新文本表单文本的 Scaffold onChange 的主体,这是行不通的。
关于我如何做到这一点有什么建议吗?
如果可能的话,我更喜欢在应用栏中显示文本表单。
下面是我的代码:
import 'package:flutter/material.dart';
import 'package:troop_mobile_app/MemberFiles/Member.dart';
import 'package:troop_mobile_app/MemberFiles/MemberList.dart';
import 'package:troop_mobile_app/DatabaseFiles/DBHelper.dart';
Future<List<Member>> search(String search) async {
var dbHelper = DBHelper();
Future<List<Member>> members = dbHelper.searchScouts(search);
return members;
}
class SearchFunction extends StatefulWidget {
@override
_SearchFunctionState createState() => _SearchFunctionState();
}
class _SearchFunctionState extends State<SearchFunction> {
TextEditingController controller = TextEditingController();
String searchText = "";
_searchResults(String text) {
return new FutureBuilder<List<Member>>(
future: search(text),
builder: (context, snapshot) {
if (snapshot.hasData) {
return MemberList(snapshot.data);
}
return Container(
alignment: AlignmentDirectional.center,
child: new CircularProgressIndicator(
strokeWidth: 7,
));
});
}
Widget build(BuildContext context) {
//Page Creation returning the UI Home Page Display
return Scaffold(
//Top 'Menu Bar' (AppBar) Creation
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
Navigator.pop(context);
},
padding: EdgeInsets.fromLTRB(
20 /*left*/, 0 /*top*/, 20 /*right*/, 0 /*bottom*/),
),
title: TextField(
//initialValue: 'Search...',
style: TextStyle(color: Colors.black),
decoration: InputDecoration(
//fillColor: Colors.white,
//filled: true,
//border:
//OutlineInputBorder(borderRadius: BorderRadius.circular(12.0)),
labelText: 'Search...',
contentPadding: EdgeInsets.fromLTRB(10, 6, 0, 6),
prefixIcon: Icon(Icons.search),
),
onChanged: (text) async {
_searchResults(text);
searchText = text;
},
controller: controller,
),
),
//End Top 'Menu Bar' Creation
//Main Body Creation
body: Container(
child: new FutureBuilder<List<Member>> (
future: search(searchText),
builder: (context, snapshot) {
if (snapshot.hasData) {
return MemberList(snapshot.data);
}
return Container(
alignment: AlignmentDirectional.center,
child: new CircularProgressIndicator(
strokeWidth: 7,
));
}),
)
//End Main Body Creation
);
}
}
成员列表:
import 'package:flutter/material.dart';
import 'MemberCards.dart';
import 'package:troop_mobile_app/MemberFiles/Member.dart';
class MemberList extends StatelessWidget {
final List<Member> members;
MemberList(this.members);
@override
Widget build(BuildContext context) {
return _buildList(context);
}
ListView _buildList(context) {
return ListView.builder(
itemCount: members.length,
itemBuilder: (context, int) {
return MemberCards(members[int], );
},
);
}
}
数据库助手:
Future<List<Map<String, dynamic>>> searchScoutsMap(String search) async {
Database db = await this.database;
print("This works? $db");
var result = await db.rawQuery("SELECT * FROM $memberTable WHERE adult = 'N' AND ($colFirstName Like '%$search%' OR $colLastName Like '%$search%') ORDER BY $colFirstName ASC, $colLastName ASC");
print("result is working? $result");
print(result.length);
return result;
}
Future<List<Member>> searchScouts(String search) async {
var searchResults = await searchScoutsMap(search); // Get 'Map List' from database
print(searchResults.length);
print(searchResults.toString());
int count = searchResults.length; // Count the number of map entries in db table
List<Member> memberList = List<Member>();
// For loop to create a 'Member List' from a 'Map List'
for (int i = 0; i < count; i++) {
print("for loop working: ${i+1}");
memberList.add(Member.fromMapObject(searchResults[i]));
}
print("completed for loop");
return memberList;
}
经过几个小时令人沮丧的工作,我终于解决了我的错误...
这是我的解决方法:
在第一个代码片段中,我遗漏了 setState()
我不得不用 setState()
包装 return 新的 FutureBuilder...
_searchResults(String text) {
return new FutureBuilder<List<Member>>(
future: search(text),
builder: (context, snapshot) {
if (snapshot.hasData) {
return MemberList(snapshot.data);
}
return Container(
alignment: AlignmentDirectional.center,
child: new CircularProgressIndicator(
strokeWidth: 7,
));
});
}
如下所示的新代码片段:
我希望这对遇到类似问题的其他人有所帮助。
_searchResults(String text) {
setState(() {
return new FutureBuilder<List<Member>>(
future: search(text),
builder: (context, snapshot) {
if (snapshot.hasData) {
return MemberList(snapshot.data);
}
return Container(
alignment: AlignmentDirectional.center,
child: new CircularProgressIndicator(
strokeWidth: 7,
));
});
});
}
我正在尝试搜索我的 sqlite 数据库,现在它 returns 所有成员,即使在文本表单中输入了文本。我在 memberList 构造函数中有一个 ListView 构建器,它为每个成员创建卡片。我想要它做的是只显示与用户输入匹配的卡片。
即如果用户输入 J,它将仅显示名字或姓氏中带有字母 J 的成员。
我可以看到查询工作正常,因为我在 dbHelper class 中打印了计数,并且每次我更改文本表单的文本时它都会更新。我需要它做的基本上是刷新文本表单文本的 Scaffold onChange 的主体,这是行不通的。
关于我如何做到这一点有什么建议吗?
如果可能的话,我更喜欢在应用栏中显示文本表单。 下面是我的代码:
import 'package:flutter/material.dart';
import 'package:troop_mobile_app/MemberFiles/Member.dart';
import 'package:troop_mobile_app/MemberFiles/MemberList.dart';
import 'package:troop_mobile_app/DatabaseFiles/DBHelper.dart';
Future<List<Member>> search(String search) async {
var dbHelper = DBHelper();
Future<List<Member>> members = dbHelper.searchScouts(search);
return members;
}
class SearchFunction extends StatefulWidget {
@override
_SearchFunctionState createState() => _SearchFunctionState();
}
class _SearchFunctionState extends State<SearchFunction> {
TextEditingController controller = TextEditingController();
String searchText = "";
_searchResults(String text) {
return new FutureBuilder<List<Member>>(
future: search(text),
builder: (context, snapshot) {
if (snapshot.hasData) {
return MemberList(snapshot.data);
}
return Container(
alignment: AlignmentDirectional.center,
child: new CircularProgressIndicator(
strokeWidth: 7,
));
});
}
Widget build(BuildContext context) {
//Page Creation returning the UI Home Page Display
return Scaffold(
//Top 'Menu Bar' (AppBar) Creation
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
Navigator.pop(context);
},
padding: EdgeInsets.fromLTRB(
20 /*left*/, 0 /*top*/, 20 /*right*/, 0 /*bottom*/),
),
title: TextField(
//initialValue: 'Search...',
style: TextStyle(color: Colors.black),
decoration: InputDecoration(
//fillColor: Colors.white,
//filled: true,
//border:
//OutlineInputBorder(borderRadius: BorderRadius.circular(12.0)),
labelText: 'Search...',
contentPadding: EdgeInsets.fromLTRB(10, 6, 0, 6),
prefixIcon: Icon(Icons.search),
),
onChanged: (text) async {
_searchResults(text);
searchText = text;
},
controller: controller,
),
),
//End Top 'Menu Bar' Creation
//Main Body Creation
body: Container(
child: new FutureBuilder<List<Member>> (
future: search(searchText),
builder: (context, snapshot) {
if (snapshot.hasData) {
return MemberList(snapshot.data);
}
return Container(
alignment: AlignmentDirectional.center,
child: new CircularProgressIndicator(
strokeWidth: 7,
));
}),
)
//End Main Body Creation
);
}
}
成员列表:
import 'package:flutter/material.dart';
import 'MemberCards.dart';
import 'package:troop_mobile_app/MemberFiles/Member.dart';
class MemberList extends StatelessWidget {
final List<Member> members;
MemberList(this.members);
@override
Widget build(BuildContext context) {
return _buildList(context);
}
ListView _buildList(context) {
return ListView.builder(
itemCount: members.length,
itemBuilder: (context, int) {
return MemberCards(members[int], );
},
);
}
}
数据库助手:
Future<List<Map<String, dynamic>>> searchScoutsMap(String search) async {
Database db = await this.database;
print("This works? $db");
var result = await db.rawQuery("SELECT * FROM $memberTable WHERE adult = 'N' AND ($colFirstName Like '%$search%' OR $colLastName Like '%$search%') ORDER BY $colFirstName ASC, $colLastName ASC");
print("result is working? $result");
print(result.length);
return result;
}
Future<List<Member>> searchScouts(String search) async {
var searchResults = await searchScoutsMap(search); // Get 'Map List' from database
print(searchResults.length);
print(searchResults.toString());
int count = searchResults.length; // Count the number of map entries in db table
List<Member> memberList = List<Member>();
// For loop to create a 'Member List' from a 'Map List'
for (int i = 0; i < count; i++) {
print("for loop working: ${i+1}");
memberList.add(Member.fromMapObject(searchResults[i]));
}
print("completed for loop");
return memberList;
}
经过几个小时令人沮丧的工作,我终于解决了我的错误...
这是我的解决方法:
在第一个代码片段中,我遗漏了 setState()
我不得不用 setState()
包装 return 新的 FutureBuilder..._searchResults(String text) {
return new FutureBuilder<List<Member>>(
future: search(text),
builder: (context, snapshot) {
if (snapshot.hasData) {
return MemberList(snapshot.data);
}
return Container(
alignment: AlignmentDirectional.center,
child: new CircularProgressIndicator(
strokeWidth: 7,
));
});
}
如下所示的新代码片段:
我希望这对遇到类似问题的其他人有所帮助。
_searchResults(String text) {
setState(() {
return new FutureBuilder<List<Member>>(
future: search(text),
builder: (context, snapshot) {
if (snapshot.hasData) {
return MemberList(snapshot.data);
}
return Container(
alignment: AlignmentDirectional.center,
child: new CircularProgressIndicator(
strokeWidth: 7,
));
});
});
}