使用 DataTable Flutter 的搜索栏布局

Gra*_*gus 3 mobile search flutter flutter-layout

我为我的列表创建了一个简单的搜索栏DataTable,但问题是我无法仅返回我搜索的项目,而是得到空字段和我搜索的项目。我已经尝试了各种方法,但我得到的错误是我需要的行和我需要的列一样多,所以这是现在我让它工作的唯一方法。

在此输入图像描述

但我想让它变成这样:

在此输入图像描述

这是代码:

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('')),
                                  ],
                                );
                        },
                      ),
                    ),
                  ),
                ),
              ],
            );
          },
        ),
      ],
    );
  }
}

Run Code Online (Sandbox Code Playgroud)

这题好像想不通 先谢谢您的帮助!

Art*_*xha 7

好吧,在您发表评论后,我终于按照我认为您想要的方式工作了。这个想法是使用两个列表而不是一个列表,并且List.generate由于该空行而不使用该方法。当您更改值时,您可以使用列表中的原始值_searchResult过滤列表。userFilteredusers

\n

我使用 DataTable 的 flutter 示例进行了这些编辑,并且它有效:

\n
import \'package:flutter/material.dart\';\n\nvoid main() => runApp(const MyApp());\n\n/// This is the main application widget.\nclass MyApp extends StatelessWidget {\n  const MyApp({Key key}) : super(key: key);\n\n  static const String _title = \'Flutter Code Sample\';\n\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      title: _title,\n      home: Scaffold(\n        appBar: AppBar(title: const Text(_title)),\n        body: MyStatelessWidget(),\n      ),\n    );\n  }\n}\n\n\nclass User{\n  String name;\n  int age;\n  String role;\n\n  User({this.name, this.age, this.role});\n}\n\n/// This is the stateless widget that the main application instantiates.\nclass MyStatelessWidget extends StatefulWidget {\n  MyStatelessWidget({Key key}) : super(key: key);\n\n  @override\n  _MyStatelessWidgetState createState() => _MyStatelessWidgetState();\n}\n\nclass _MyStatelessWidgetState extends State<MyStatelessWidget> {\n  List<User> users = [User(name: "Sarah", age: 19, role: "Student"), User(name: "Janine", age: 43, role: "Professor")];\n  List<User> usersFiltered = [];\n  TextEditingController controller = TextEditingController();\n  String _searchResult = \'\';\n\n  @override\n  void initState() {\n    super.initState();\n    usersFiltered = users;\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return Column(\n      children: [\n        Card(\n          child: new ListTile(\n            leading: new Icon(Icons.search),\n            title: new TextField(\n                controller: controller,\n                decoration: new InputDecoration(\n                    hintText: \'Search\', border: InputBorder.none),\n                onChanged: (value) {\n                  setState(() {\n                    _searchResult = value;\n                     usersFiltered = users.where((user) => user.name.contains(_searchResult) || user.role.contains(_searchResult)).toList();\n                  });\n                }),\n            trailing: new IconButton(\n              icon: new Icon(Icons.cancel),\n              onPressed: () {\n                setState(() {\n                  controller.clear();\n                  _searchResult = \'\';\n                  usersFiltered = users;\n                });\n              },\n            ),\n          ),\n        ),\n        DataTable(\n          columns: const <DataColumn>[\n            DataColumn(\n              label: Text(\n                \'Name\',\n                style: TextStyle(fontStyle: FontStyle.italic),\n              ),\n            ),\n            DataColumn(\n              label: Text(\n                \'Age\',\n                style: TextStyle(fontStyle: FontStyle.italic),\n              ),\n            ),\n            DataColumn(\n              label: Text(\n                \'Role\',\n                style: TextStyle(fontStyle: FontStyle.italic),\n              ),\n            ),\n          ],\n          rows: List.generate(usersFiltered.length, (index) =>\n              DataRow(\n                cells: <DataCell>[\n                  DataCell(Text(usersFiltered[index].name)),\n                  DataCell(Text(usersFiltered[index].age.toString())),\n                  DataCell(Text(usersFiltered[index].role)),\n                ],\n              ),\n          ),\n        ),\n      ],\n    );\n  }\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n

旧帖子:

\n

我正在寻找一种过滤数据表的方法,您的问题解决了我的问题(我现在会尽力帮助您!)。通过使用PaginatoredDataTable小部件而不是 DataTable,我可以实现您想要的结果。这个想法是在将列表传递给源属性之前对其进行过滤。这是我用来过滤列表的代码的一部分。在开关块内,我对其进行过滤以删除其他元素:

\n
switch(filter){\n        case "Id d\'exp\xc3\xa9dition":\n          expeditionsList = expeditionsList.where((e) => e.expeditionId.toLowerCase() == stringToSearch.toLowerCase()).toList();\n          break;\n      }\n\nreturn PaginatedDataTable(\n      showCheckboxColumn: false,\n      rowsPerPage: 5,\n      source: DataTableSourceExpedition(\n          expeditions: expeditionsList,\n          onRowClicked: (index) async {\n            await ExpeditionRowDialog.buildExpeditionRowDialog(\n                    context, expeditionsList[index].expeditionsDetails)\n                .show();\n          },\n      header: Container(\n        width: 100,\n        child: Text("Exp\xc3\xa9ditions"),\n      ),\n      columns: [\n        DataColumn(\n            label: Text("Id d\'exp\xc3\xa9dition"), numeric: false, tooltip: "id"),\n        \n      ],\n    );\n
Run Code Online (Sandbox Code Playgroud)\n

然后我需要使用需要DataTableSource对象的 source 属性将数据传递到表。我创建了一个扩展DataTableSource的单独类。我将过滤后的列表作为此类的参数传递,并重写 DataTableSource 类的方法:

\n
class DataTableSourceExpedition extends DataTableSource {\n    List<Expedition> expeditions = List();\n    Function onRowClicked;\n    Function onDeleteIconClick;\n    final df = DateFormat(\'dd.MM.yyyy\');\n\n   DataTableSourceExpedition({this.expeditions, this.onRowClicked, \n      this.onDeleteIconClick});\n       DataRow getRow(int index) {\n       final _expedition = expeditions[index];\n\nreturn DataRow.byIndex(\n    index: index,\n    cells: <DataCell>[\n      DataCell(Text("${_expedition.expeditionId}")),\n      DataCell(IconButton(\n        icon: Icon(Icons.delete_forever, color: kReturnColor,),\n        onPressed: (){onDeleteIconClick(index);},\n      ))\n    ],\n    onSelectChanged: (b) => onRowClicked(index));\n  }\n\n\n  bool get isRowCountApproximate => false;\n\n\n  int get rowCount => expeditions.length;\n\n\n  int get selectedRowCount => 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

像这样,我可以过滤唯一的项目,而无需添加空行,如下图所示:

\n

仅包含一行已过滤的分页数据表

\n

如果列表为空,它也有效。

\n