表格是在应用程序中高效组织数据的有用工具。Flutter 的最新更新引入了 TwoDimensionalScrollView 小部件。
TwoDimensionalScrollView 是一个小部件,它结合了 TwoDimensionalScrollable 和 TwoDimensionalViewport 在垂直和水平维度上创建内容的交互式滚动窗格,但直接使用它有点具有挑战性。
下面是在 Flutter 中实现 2D ScrollView 的演示代码。
Flutter 的预构建 widget 具有出色的性能,仅当子视图位于视图中时才延迟渲染子视图,从而提高了性能,但 Flutter 发布了一个新包 two_dimensional_scrollables 来实现在垂直轴和水平轴上滚动的 TableView。
在本教程中,我们将探索这个包来实现一个非常简单的 Tableview,并了解如何自定义它。
您可以在这里[1]找到完整的源代码。
要添加依赖项,请首先打开 pubspec.yaml 文件,然后添加依赖项。
dependencies: two_dimensional_scrollables: <latest version>
添加 TableView 时,可以使用两个构造函数:
让我们创建一个简单的 Tableview 来显示以下信息。
class Employee { final String id; final String name; final String role; final String email; Employee({ required this.id, required this.name, required this.role, required this.email}); static get getEmployees{ return [ Employee(id: '1', name: 'John Doe', role: 'Manager', email: 'john@example.com'), Employee(id: '2', name: 'Jane Smith', role: 'Developer', email: 'jane@example.com'), Employee(id: '3', name: 'Mike Johnson', role: 'Designer', email: 'mike@example.com'), Employee(id: '4', name: 'Emily Brown', role: 'HR Specialist',email: 'emily@example.com'), Employee(id: '5', name: 'Alex Lee', role: 'Marketing Analyst', email: 'alex@example.com'), Employee(id: '6', name: 'John Doe', role: 'Manager', email: 'john@example.com'), Employee(id: '7', name: 'Jane Smith', role: 'Developer', email: 'jane@example.com'), Employee(id: '8', name: 'Mike Johnson', role: 'Designer', email: 'mike@example.com'), Employee(id: '9', name: 'Emily Brown', role: 'HR Specialist',email: 'emily@example.com'), Employee(id: '10', name: 'Alex Lee', role: 'Marketing Analyst', email: 'alex@example.com'), ]; }}
这是 TableView.builder 的基本示例代码。
class TwoDimensionalScrollableDemo extends StatelessWidget { TwoDimensionalScrollableDemo({super.key});final List<Employee> employees = Employee.getEmployees; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("Table view Demo"), ), body: TableView.builder( columnCount: 2, rowCount: 11, columnBuilder: buildTableSpan, rowBuilder: buildTableSpan, cellBuilder: (BuildContext context, TableVicinity vicinity) { return Container(child: Center(child: addText(vicinity))); }), ); } TableSpan buildTableSpan(int index){ return TableSpan(extent: FixedTableSpanExtent(50)); } Widget addText(TableVicinity vicinity) { if (vicinity.yIndex == 0 && vicinity.xIndex == 0) { return const Text("Index"); } else if (vicinity.yIndex == 0 && vicinity.xIndex == 1) { return const Text("name"); } else if (vicinity.xIndex == 0) { return Text(employees[vicinity.yIndex-1].id); } else if (vicinity.xIndex == 1) { return Text(employees[vicinity.yIndex-1].name); } return Text(""); }}
这对于几行代码来说已经相当不错了,让我们分解一下 TableView.builder 所需的参数。
运行上面的代码,您将看到以下输出。
图片
现在,让我们研究一下 TableView.builder 提供的功能!那么,让我们看看如何自定义和控制 TableView 并添加更多功能。
TableSpan 表示 TableView 中的一行或一列。
TableSpan buildTableSpan(int index) { TableSpanDecoration decoration = const TableSpanDecoration( border: TableSpanBorder( trailing: BorderSide(color: Colors.black), leading: BorderSide(color: Colors.black))); return TableSpan( extent: const FixedTableSpanExtent(100), foregroundDecoration: decoration);}
TableSpanDecoration 类用于指定 TableSpan 的装饰。我们可以通过 TableSpanBorder 类中的 border 参数为 TableSpan 添加边框,该类具有代表行左右边框和列上下边框的拖尾和前导属性。
TableSpan buildTableSpan(int index) { TableSpanDecoration decoration = TableSpanDecoration( color: index == 0 ? Colors.grey[300] : null, border: const TableSpanBorder( trailing: BorderSide(color: Colors.black), leading: BorderSide(color: Colors.black))); return TableSpan( extent: const FixedTableSpanExtent(100), backgroundDecoration: decoration);}
TableSpanDecoration 中的 color 属性用于设置 TableSpan 的颜色。
运行代码,输出将如下所示
图片
因为
这里默认的轴是 Axis.vertical ,所以,先绘制列,然后绘制行,边框与行装饰重叠,所以,让我们为前景装饰添加边框。
TableSpan buildTableSpan(int index) { TableSpanDecoration foreGroundDecoration = const TableSpanDecoration( border: TableSpanBorder( trailing: BorderSide(color: Colors.black), leading: BorderSide(color: Colors.black))); TableSpanDecoration backGroundDecoration = TableSpanDecoration( color: index == 0 ? Colors.grey[300] : null, ); return TableSpan( extent: const FixedTableSpanExtent(100), backgroundDecoration: backGroundDecoration, foregroundDecoration: foreGroundDecoration);}
在前景装饰中添加边框可确保其呈现在 TableView 中单元格内容的顶部。
图片
它表示行的高度和列的宽度,TableSpanExtent 有四种类型。
具有固定[像素]的跨度。
extent: const FixedTableSpanExtent(50),
图片
它将跨度范围指定为视口范围的一部分。它与 Expanded 小部件相同,根据提供的分数占用空间。
extent: const FractionalTableSpanExtent(0.5),
图片
它指定跨度应占据视口中的剩余空间。
TableSpan buildColumnSpan(int index) { TableSpanDecoration decoration = const TableSpanDecoration( border: TableSpanBorder( trailing: BorderSide(color: Colors.black), leading: BorderSide(color: Colors.black))); return TableSpan( extent: index==0? FixedTableSpanExtent(100):RemainingTableSpanExtent(), backgroundDecoration: decoration);}
图片
它以两个范围作为参数,并通过组合器函数运行这两个范围的结果。
TableSpan buildRowSpan(int index) { TableSpanExtent extent1 = FixedTableSpanExtent(100); TableSpanExtent extent2 = FixedTableSpanExtent(100); double combiner(double value1, double value2) { return value1 + value2; } TableSpanDecoration foreGroundDecoration = const TableSpanDecoration( border: TableSpanBorder( trailing: BorderSide(color: Colors.black), leading: BorderSide(color: Colors.black))); TableSpanDecoration backGroundDecoration = TableSpanDecoration( color: index == 0 ? Colors.grey[300] : null, ); if (index == 1) { return TableSpan( extent: CombiningTableSpanExtent(extent1, extent2, combiner), backgroundDecoration: backGroundDecoration, foregroundDecoration: foreGroundDecoration); } return TableSpan( extent: const FixedTableSpanExtent(100), backgroundDecoration: backGroundDecoration, foregroundDecoration: foreGroundDecoration); }
图片
当鼠标指针(按下或不按下按钮)进入此跨度描述的行或列时触发。
void Function(PointerEnterEvent)? onEnter
当鼠标指针(按下或未按下按钮)退出此跨度描述的行或列时,它会触发。
void Function(PointerExitEvent)? onExit
recognizerFactories: <Type, GestureRecognizerFactory>{ TapGestureRecognizer: GestureRecognizerFactoryWithHandlers<TapGestureRecognizer>( () => TapGestureRecognizer(), (TapGestureRecognizer t) { t.notallow=(TapDownDetails tapdownDetails){ print(tapdownDetails.localPosition); }; t.notallow=(TapUpDetails tapupDetails){ print(tapupDetails.localPosition); }; } ),},
recognizerFactories 是一个映射,其中键是手势类型,值是 GestureRecognizerFactory 的实例。
GestureRecognizerFactoryWithHandlers 有两个参数。调用时返回 TapGestureRecognizer 实例的函数和初始化 TapGestureRecognizer 并设置事件处理程序以处理特定事件详细信息的回调函数。
padding 属性用于为每行和每列添加填充。
padding: TableSpanPadding(leading: 10),
让我们在 TableView 中显示来自 Employee 类的更多数据,例如 email 和 role 。
Widget addText(TableVicinity vicinity) { if (vicinity.yIndex == 0 && vicinity.xIndex == 0) { return const Text("Index"); } else if (vicinity.yIndex == 0 && vicinity.xIndex == 1) { return const Text("name"); } else if (vicinity.yIndex == 0 && vicinity.xIndex == 2) { return const Text("Email"); } else if (vicinity.yIndex == 0 && vicinity.xIndex == 3) { return const Text("Role"); } else if (vicinity.xIndex == 0) { return Text(employees[vicinity.yIndex - 1].id); } else if (vicinity.xIndex == 1) { return Text(employees[vicinity.yIndex - 1].name); } else if (vicinity.xIndex == 2) { return Text(employees[vicinity.yIndex - 1].email); } else if (vicinity.xIndex == 3) { return Text(employees[vicinity.yIndex - 1].role); } return Text(""); }... body: TableView.builder( mainAxis: Axis.horizontal, columnCount: 4, rowCount: 21, columnBuilder: buildColumnSpan, rowBuilder: buildTableSpan, cellBuilder: (BuildContext context, TableVicinity vicinity) { return Center(child: addText(vicinity)); }),...TableSpan buildColumnSpan(int index) { TableSpanDecoration decoration = const TableSpanDecoration( border: TableSpanBorder( trailing: BorderSide(color: Colors.black), leading: BorderSide(color: Colors.black))); if (index == 2) { return TableSpan( extent: const RemainingTableSpanExtent(), backgroundDecoration: decoration, ); } else if (index == 3) { return TableSpan( extent: const FractionalTableSpanExtent(0.5), backgroundDecoration: decoration, ); } return TableSpan( extent: FixedTableSpanExtent(100), backgroundDecoration: decoration);}
输出是:
图片
固定持续出现在 TableView 视口边缘的特定数量的行和列。
TableView.builder(... pinnedRowCount: 1, pinnedColumnCount: 1, ),
图片
ScrollableDetail 允许对小部件的垂直和水平滚动行为进行特定配置。
verticalDetails: ScrollableDetails.vertical( reverse: true, controller: verticalController, physics: const AlwaysScrollableScrollPhysics(), decorationClipBehavior: Clip.hardEdge),
ScrollableDetails 中的 verticalDetails 允许对小部件的垂直滚动行为进行特定配置,它封装了各种属性。
verticalDetails: ScrollableDetails.vertical( reverse: true, controller: verticalController, physics: const AlwaysScrollableScrollPhysics(), decorationClipBehavior: Clip.hardEdge,)
以下是属性的详细说明:
cacheExtent: 200,
与ListView类似, cacheExtent 是在进入屏幕可见部分之前绘制的区域的大小。
该枚举允许开发人员指定如何使用 kTouchSlop 处理对角滚动。
在本教程中,我们学习了如何使用 Flutter 中的 two_dimensional_scrollable 实现 Flutter 中的 tableView,我们可以用它做更多的事情并使用它添加更多功能。这是我对 Flutter 中 TableView 的一个小介绍。
翻译自:https://blog.canopas.com/how-to-implement-2d-scrollable-tableview-in-flutter-a8b0fe703614图片
[1]这里: https://gist.github.com/cp-sneha-s/d2375b2a624f5650fa3836a84805b15f
本文链接:http://www.28at.com/showinfo-26-100463-0.html如何在 Flutter 中实现 2D 可滚动的表格,探索 Flutter 中的二维可滚动项,表格解决方案
声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com
上一篇: 一文带您理解Python的map/filter/reduce
下一篇: 基于Rspack实现大仓应用构建提效实践