使用 DataTable Flutter 的搜索栏布局
Search Bar Layout with DataTable Flutter
我为我的 DataTable
列表制作了一个简单的搜索栏,但问题是我不能 return 只搜索我搜索的项目,而是我得到空字段和项目我寻找。我已经尝试了各种方法,但我得到的错误是我需要的行和列一样多,所以这是目前唯一可行的方法。
但我想让它变成这样:
代码如下:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'models/vehicle.dart';
import 'services/vehicle_api.dart';
import 'models/vehicle_data_provider.dart';
class VehicleList extends StatefulWidget {
@override
_VehicleList createState() => _VehicleList();
}
class _VehicleList extends State<VehicleList> {
TextEditingController controller = TextEditingController();
String _searchResult = '';
_getPosts() async {
HomePageProvider provider =
Provider.of<HomePageProvider>(context, listen: false);
var postsResponse = await fetchVehicles();
if (postsResponse.isSuccessful) {
provider.setPostsList(postsResponse.data, notify: false);
} else {
provider.mergePostsList(
postsResponse.data,
);
}
provider.setIsHomePageProcessing(false);
}
@override
void initState() {
_getPosts();
super.initState();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Card(
child: new ListTile(
leading: new Icon(Icons.search),
title: new TextField(
controller: controller,
decoration: new InputDecoration(
hintText: 'Search', border: InputBorder.none),
onChanged: (value) {
setState(() {
_searchResult = value;
});
}),
trailing: new IconButton(
icon: new Icon(Icons.cancel),
onPressed: () {
setState(() {
controller.clear();
_searchResult = '';
});
},
),
),
),
Consumer<HomePageProvider>(
builder: (context, vehicleData, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Container(
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.all(
Radius.circular(12.0),
),
),
child: SingleChildScrollView(
child: DataTable(
columnSpacing: 30,
columns: <DataColumn>[
DataColumn(
numeric: false,
label: Text(
'Friendly Name',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
DataColumn(
label: Text(
'Licence Plate',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
DataColumn(
label: Text(
'Delete',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
],
rows: List.generate(
vehicleData.postsList.length,
(index) {
VehicleData post = vehicleData.getPostByIndex(index);
return post.licencePlate
.toLowerCase()
.contains(_searchResult) ||
'${post.model}'
.toLowerCase()
.contains(_searchResult) ||
'${post.make}'
.toLowerCase()
.contains(_searchResult) ||
post.type
.toLowerCase()
.contains(_searchResult)
? DataRow(
cells: <DataCell>[
DataCell(
Text('${post.friendlyName}'),
),
DataCell(
Text('${post.licencePlate}'),
),
DataCell(
IconButton(
icon: Icon(Icons.delete),
onPressed: () {
vehicleData.deletePost(post);
},
),
),
],
)
: DataRow(
/// This is the part where I return empty rows with one row with the search bar results, so I assume this must me changed
cells: <DataCell>[
DataCell(Text('')),
DataCell(Text('')),
DataCell(Text('')),
],
);
},
),
),
),
),
],
);
},
),
],
);
}
}
似乎无法弄清楚这一点。在此先感谢您的帮助!
好的,在你发表评论后,我终于让它按照我想的那样工作了。这个想法是使用两个列表而不是一个列表,并且由于该空行而不使用 List.generate
方法。当您更改 _searchResult
值时,您会使用来自 users
列表的原始值过滤 userFiltered
列表。
我在这些编辑中使用了 DataTable 的 flutter 示例,它有效:
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
/// This is the main application widget.
class MyApp extends StatelessWidget {
const MyApp({Key key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
@override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: MyStatelessWidget(),
),
);
}
}
class User{
String name;
int age;
String role;
User({this.name, this.age, this.role});
}
/// This is the stateless widget that the main application instantiates.
class MyStatelessWidget extends StatefulWidget {
MyStatelessWidget({Key key}) : super(key: key);
@override
_MyStatelessWidgetState createState() => _MyStatelessWidgetState();
}
class _MyStatelessWidgetState extends State<MyStatelessWidget> {
List<User> users = [User(name: "Sarah", age: 19, role: "Student"), User(name: "Janine", age: 43, role: "Professor")];
List<User> usersFiltered = [];
TextEditingController controller = TextEditingController();
String _searchResult = '';
@override
void initState() {
super.initState();
usersFiltered = users;
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Card(
child: new ListTile(
leading: new Icon(Icons.search),
title: new TextField(
controller: controller,
decoration: new InputDecoration(
hintText: 'Search', border: InputBorder.none),
onChanged: (value) {
setState(() {
_searchResult = value;
usersFiltered = users.where((user) => user.name.contains(_searchResult) || user.role.contains(_searchResult)).toList();
});
}),
trailing: new IconButton(
icon: new Icon(Icons.cancel),
onPressed: () {
setState(() {
controller.clear();
_searchResult = '';
usersFiltered = users;
});
},
),
),
),
DataTable(
columns: const <DataColumn>[
DataColumn(
label: Text(
'Name',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
DataColumn(
label: Text(
'Age',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
DataColumn(
label: Text(
'Role',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
],
rows: List.generate(usersFiltered.length, (index) =>
DataRow(
cells: <DataCell>[
DataCell(Text(usersFiltered[index].name)),
DataCell(Text(usersFiltered[index].age.toString())),
DataCell(Text(usersFiltered[index].role)),
],
),
),
),
],
);
}
}
旧 POST:
我正在寻找一种过滤数据的方法table,你的问题解决了我的问题,谢谢(我现在会尽力帮助你!)。通过使用 PaginatedDataTable 小部件而不是 DataTable,我可以实现您想要的结果。这个想法是在将列表传递给源 属性 之前过滤列表。这是我用来过滤列表的代码的一部分。在开关块内,我过滤它以删除其他元素:
switch(filter){
case "Id d'expédition":
expeditionsList = expeditionsList.where((e) => e.expeditionId.toLowerCase() == stringToSearch.toLowerCase()).toList();
break;
}
return PaginatedDataTable(
showCheckboxColumn: false,
rowsPerPage: 5,
source: DataTableSourceExpedition(
expeditions: expeditionsList,
onRowClicked: (index) async {
await ExpeditionRowDialog.buildExpeditionRowDialog(
context, expeditionsList[index].expeditionsDetails)
.show();
},
header: Container(
width: 100,
child: Text("Expéditions"),
),
columns: [
DataColumn(
label: Text("Id d'expédition"), numeric: false, tooltip: "id"),
],
);
然后我需要使用需要 DataTableSource 对象的源 属性 将数据传递给 table。我创建了一个单独的 class,它扩展了 DataTableSource。我将过滤后的列表作为此 class 的参数传递并覆盖 DataTableSource class:
的方法
class DataTableSourceExpedition extends DataTableSource {
List<Expedition> expeditions = List();
Function onRowClicked;
Function onDeleteIconClick;
final df = DateFormat('dd.MM.yyyy');
DataTableSourceExpedition({this.expeditions, this.onRowClicked,
this.onDeleteIconClick});
DataRow getRow(int index) {
final _expedition = expeditions[index];
return DataRow.byIndex(
index: index,
cells: <DataCell>[
DataCell(Text("${_expedition.expeditionId}")),
DataCell(IconButton(
icon: Icon(Icons.delete_forever, color: kReturnColor,),
onPressed: (){onDeleteIconClick(index);},
))
],
onSelectChanged: (b) => onRowClicked(index));
}
bool get isRowCountApproximate => false;
int get rowCount => expeditions.length;
int get selectedRowCount => 0;
}
像这样,我可以在不需要添加空行的情况下过滤唯一的项目,如下图所示:
如果列表为空,它也有效。
我为我的 DataTable
列表制作了一个简单的搜索栏,但问题是我不能 return 只搜索我搜索的项目,而是我得到空字段和项目我寻找。我已经尝试了各种方法,但我得到的错误是我需要的行和列一样多,所以这是目前唯一可行的方法。
但我想让它变成这样:
代码如下:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'models/vehicle.dart';
import 'services/vehicle_api.dart';
import 'models/vehicle_data_provider.dart';
class VehicleList extends StatefulWidget {
@override
_VehicleList createState() => _VehicleList();
}
class _VehicleList extends State<VehicleList> {
TextEditingController controller = TextEditingController();
String _searchResult = '';
_getPosts() async {
HomePageProvider provider =
Provider.of<HomePageProvider>(context, listen: false);
var postsResponse = await fetchVehicles();
if (postsResponse.isSuccessful) {
provider.setPostsList(postsResponse.data, notify: false);
} else {
provider.mergePostsList(
postsResponse.data,
);
}
provider.setIsHomePageProcessing(false);
}
@override
void initState() {
_getPosts();
super.initState();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Card(
child: new ListTile(
leading: new Icon(Icons.search),
title: new TextField(
controller: controller,
decoration: new InputDecoration(
hintText: 'Search', border: InputBorder.none),
onChanged: (value) {
setState(() {
_searchResult = value;
});
}),
trailing: new IconButton(
icon: new Icon(Icons.cancel),
onPressed: () {
setState(() {
controller.clear();
_searchResult = '';
});
},
),
),
),
Consumer<HomePageProvider>(
builder: (context, vehicleData, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Container(
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.all(
Radius.circular(12.0),
),
),
child: SingleChildScrollView(
child: DataTable(
columnSpacing: 30,
columns: <DataColumn>[
DataColumn(
numeric: false,
label: Text(
'Friendly Name',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
DataColumn(
label: Text(
'Licence Plate',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
DataColumn(
label: Text(
'Delete',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
],
rows: List.generate(
vehicleData.postsList.length,
(index) {
VehicleData post = vehicleData.getPostByIndex(index);
return post.licencePlate
.toLowerCase()
.contains(_searchResult) ||
'${post.model}'
.toLowerCase()
.contains(_searchResult) ||
'${post.make}'
.toLowerCase()
.contains(_searchResult) ||
post.type
.toLowerCase()
.contains(_searchResult)
? DataRow(
cells: <DataCell>[
DataCell(
Text('${post.friendlyName}'),
),
DataCell(
Text('${post.licencePlate}'),
),
DataCell(
IconButton(
icon: Icon(Icons.delete),
onPressed: () {
vehicleData.deletePost(post);
},
),
),
],
)
: DataRow(
/// This is the part where I return empty rows with one row with the search bar results, so I assume this must me changed
cells: <DataCell>[
DataCell(Text('')),
DataCell(Text('')),
DataCell(Text('')),
],
);
},
),
),
),
),
],
);
},
),
],
);
}
}
似乎无法弄清楚这一点。在此先感谢您的帮助!
好的,在你发表评论后,我终于让它按照我想的那样工作了。这个想法是使用两个列表而不是一个列表,并且由于该空行而不使用 List.generate
方法。当您更改 _searchResult
值时,您会使用来自 users
列表的原始值过滤 userFiltered
列表。
我在这些编辑中使用了 DataTable 的 flutter 示例,它有效:
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
/// This is the main application widget.
class MyApp extends StatelessWidget {
const MyApp({Key key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
@override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: MyStatelessWidget(),
),
);
}
}
class User{
String name;
int age;
String role;
User({this.name, this.age, this.role});
}
/// This is the stateless widget that the main application instantiates.
class MyStatelessWidget extends StatefulWidget {
MyStatelessWidget({Key key}) : super(key: key);
@override
_MyStatelessWidgetState createState() => _MyStatelessWidgetState();
}
class _MyStatelessWidgetState extends State<MyStatelessWidget> {
List<User> users = [User(name: "Sarah", age: 19, role: "Student"), User(name: "Janine", age: 43, role: "Professor")];
List<User> usersFiltered = [];
TextEditingController controller = TextEditingController();
String _searchResult = '';
@override
void initState() {
super.initState();
usersFiltered = users;
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Card(
child: new ListTile(
leading: new Icon(Icons.search),
title: new TextField(
controller: controller,
decoration: new InputDecoration(
hintText: 'Search', border: InputBorder.none),
onChanged: (value) {
setState(() {
_searchResult = value;
usersFiltered = users.where((user) => user.name.contains(_searchResult) || user.role.contains(_searchResult)).toList();
});
}),
trailing: new IconButton(
icon: new Icon(Icons.cancel),
onPressed: () {
setState(() {
controller.clear();
_searchResult = '';
usersFiltered = users;
});
},
),
),
),
DataTable(
columns: const <DataColumn>[
DataColumn(
label: Text(
'Name',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
DataColumn(
label: Text(
'Age',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
DataColumn(
label: Text(
'Role',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
],
rows: List.generate(usersFiltered.length, (index) =>
DataRow(
cells: <DataCell>[
DataCell(Text(usersFiltered[index].name)),
DataCell(Text(usersFiltered[index].age.toString())),
DataCell(Text(usersFiltered[index].role)),
],
),
),
),
],
);
}
}
旧 POST:
我正在寻找一种过滤数据的方法table,你的问题解决了我的问题,谢谢(我现在会尽力帮助你!)。通过使用 PaginatedDataTable 小部件而不是 DataTable,我可以实现您想要的结果。这个想法是在将列表传递给源 属性 之前过滤列表。这是我用来过滤列表的代码的一部分。在开关块内,我过滤它以删除其他元素:
switch(filter){
case "Id d'expédition":
expeditionsList = expeditionsList.where((e) => e.expeditionId.toLowerCase() == stringToSearch.toLowerCase()).toList();
break;
}
return PaginatedDataTable(
showCheckboxColumn: false,
rowsPerPage: 5,
source: DataTableSourceExpedition(
expeditions: expeditionsList,
onRowClicked: (index) async {
await ExpeditionRowDialog.buildExpeditionRowDialog(
context, expeditionsList[index].expeditionsDetails)
.show();
},
header: Container(
width: 100,
child: Text("Expéditions"),
),
columns: [
DataColumn(
label: Text("Id d'expédition"), numeric: false, tooltip: "id"),
],
);
然后我需要使用需要 DataTableSource 对象的源 属性 将数据传递给 table。我创建了一个单独的 class,它扩展了 DataTableSource。我将过滤后的列表作为此 class 的参数传递并覆盖 DataTableSource class:
的方法class DataTableSourceExpedition extends DataTableSource {
List<Expedition> expeditions = List();
Function onRowClicked;
Function onDeleteIconClick;
final df = DateFormat('dd.MM.yyyy');
DataTableSourceExpedition({this.expeditions, this.onRowClicked,
this.onDeleteIconClick});
DataRow getRow(int index) {
final _expedition = expeditions[index];
return DataRow.byIndex(
index: index,
cells: <DataCell>[
DataCell(Text("${_expedition.expeditionId}")),
DataCell(IconButton(
icon: Icon(Icons.delete_forever, color: kReturnColor,),
onPressed: (){onDeleteIconClick(index);},
))
],
onSelectChanged: (b) => onRowClicked(index));
}
bool get isRowCountApproximate => false;
int get rowCount => expeditions.length;
int get selectedRowCount => 0;
}
像这样,我可以在不需要添加空行的情况下过滤唯一的项目,如下图所示:
如果列表为空,它也有效。