【Flutter实现表格上下左右滚动】9.29
一、需求以及设计效果:
- 水平滑动时,表格第一列和第二列固定不动;
- 铅直滑动时,表格第一行固定不动;
一、设计思路
(1)样式绘制:将表格划分为四块;
- 左下两列,绘制成一个表格,只可上下滑动;
- 左上两列,绘制成固定表格,不可滑动;
- 右下多行,绘制为一个表格,可上下滑动,也可左右滑动;
- 右上一行,绘制为一个表格,只可左右滑动;
(2)动效实现:
二、具体实现
(1)绘制页面布局:
-
Container->
-
Row->
//第一列
-
Container(
-
Column(
// 固定首行—Table
// 其余行—Table ) ),
//第二列
//创建第一列tableRow
TableRow _buildSingleColumnOne(int index) {
return TableRow(
children: [
_buildSideBox(index == -1 ? '第一列' : "软件质量管理", index == -1),
_buildSideBox(index == -1 ? '第二列' : "软件质量管理", index == -1),
]);
}
//创建单个表格
Widget _buildSideBox(String title, isTitle) {
return SizedBox(
height: numRowHeight,
width: numRowWidth,
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(width: 0.33, color:Colors.black),
top: BorderSide(width: 0.33, color:Colors.black),
right: BorderSide(width: 0.33, color:Colors.black),
left: BorderSide(width: 0.33, color:Colors.black),
)
),
child: Text(
title,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: isTitle ? 14 : 12, color: Colors.black),
))
);
}
(二)、滑动控制:上下左右相互关联
三、问题以及解决汇总
1. A RenderFlex overflowed by 357 pixels on the right.
* 原因:子组件的内容超出父组件,但子组件仍然按照真实大小显示。
* 解决:添加弹性组件,如Expanded、ListView
*注意:
①Expanded水平方向(Row)使内容自动适配,不能用于调整垂直Column,若解决参见(https://blog.csdn.net/kaixuan_dashen/article/details/102308861)
②ListView垂直方向,可使内容自动适配
③Expanded、Flexible只在Row、Column等组件内,不在其他组件内使用。
④Expanded、Flexible两个的默认灵活系数是一样的,但是fit参数不同,Expanded是默认要占满分配的空间的,而Flexible则默认不需要
⑤Scafflod必须封装在MaterialApp中
2.滚动控制:
* 问题:①如何使得表格既能上下滚动,又能左右滚动?
* 解决:给控制横向布局和纵向布局的组件上都加上滑动控制
Expanded(
child:
ListView(//纵向
controller: thirdColumnController,//纵向滑动控制
children:[
SingleChildScrollView(//横向
controller:secondedRowController ,//横向滑动控制
scrollDirection: Axis.horizontal,
child:
Row(
children:[
Container(
child: Table(children: _buildTableRow()),
width: numRowWidth*6 ,//设置列的行宽 )
]),),],),),
* 问题:②ScrollController firstColumnController = ScrollController();其中的参数有什么意义?不懂
3.组件使用:
(1)table:
* 注意:children:[]子组件必须为单个 ; tableRow;children:XX,XX子组件可以为列表
Table(
//设置边框
border: TableBorder.all(
color: Colors.black,
),
columnWidths: const{
//列宽
0: FixedColumnWidth(100.0),
1: FixedColumnWidth(100.0),
},
//表格具体内容
children: [
//表格第一行
TableRow(
children: [
SizedBox(//设置行高
height: 50.0,
child:Text('职责'),
),
//第一行的第一列
Text('重点工作'),
//第一行的第二列
Text('工作内容'),
]
),
//表格第二行
TableRow()
]
),
],
(2)ScrollController
//定义可控制滚动组件
ScrollController firstColumnController = ScrollController();
//监听滚动
firstColumnController.addListener(() {
if (firstColumnController.offset != secondedColumnController.offset) {
secondedColumnController.jumpTo(firstColumnController.offset) ;
} }
//监听滚动效果
NotificationListener(
onNotification: (ScrollNotification notification) {
print("监听到滚动");
if (notification is ScrollStartNotification) {
print("开始滚动");
}
if (notification is ScrollUpdateNotification) {
print("正在滚动... , 当前滚动的位置 ${notification.metrics.pixels} ListView总高度${notification.metrics.maxScrollExtent}");
}
if (notification is ScrollEndNotification) {
print("结束滚动");
}
return true; //返回 true 表示监听到的方法不向上冒泡
//监听滚动组件:
child: Container()
},
(3)table拆分为两部分
思路:将Table-tableRow(
将行封装成列表,
将行中的每格列再封装成tableRow(单个)
)
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() => runApp(MineApp());
class MineApp extends StatefulWidget{
@override
_MineAppState createState() => _MineAppState();
}
class _MineAppState extends State<MineApp>{
//定义表格行高\宽
double table_height = 20;
double table_width = 100;
//定义单个表格
Widget buildTableBox(String info){
return Container(
height: table_height,
width: table_width,
alignment: Alignment.center,
child: Text(info),
);
}
//创建一行TableRow(可以只包含一列的一行)
List<TableRow> buildOneTableRow(int num){
//定义行数
List<TableRow> TableList = List();
for(int i = 0; i < num; i++) {
TableList.add(buildTableRow());
}
return TableList ;
}
//创建列
TableRow buildTableColumn(){
return TableRow(
children: [
buildTableBox("列")
],
);
}
//创建行
TableRow buildTableRow(){
return TableRow(
children: [
//定义行中的列
buildTableBox("1"),
buildTableBox("2"),
buildTableBox("3"),
buildTableBox("4"),
],
);
}
@override
Widget build(BuildContext context){
return MaterialApp(
home:Scaffold(
body: Table(
children: buildOneTableRow(5),
),
),
);
}
}
4.:
* 问题:②ScrollController firstColumnController = ScrollController();其中的参数有什么意义?不懂
四、性能优化:
1. 将前两列,分别绘制,水平方向需要关联三个滑动控制。
* 解决:优化结构
五、感谢链接:
https://blog.csdn.net/WZAHD/article/details/105582936
六、全部代码
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:zos/widgets/common/status_bar.dart';
void main()=>runApp(YearPlanTest());
class YearPlanTest extends StatelessWidget{
@override
Widget build(BuildContext context) {
return MaterialApp(
title:'表格绘制',
home: YearPlan (),
);
}
}
class YearPlan extends StatefulWidget {
@override
_YearPlanState createState() => _YearPlanState();
}
class _YearPlanState extends State<YearPlan>{
//定义可控制滚动组件
ScrollController firstColumnController = ScrollController();
ScrollController thirdColumnController = ScrollController();
ScrollController firstRowController = ScrollController();
ScrollController secondedRowController = ScrollController();
//创建第一列行
double numRowWidth = 100.0;//单个表宽
double numRowHeight = 48.0;//表格高
List<TableRow> _buildTableColumnOne() {
List<TableRow> returnList = new List();
returnList.add(_buildSingleColumnOne(-1));
for (int i = 0; i < 5; i++) {
returnList.add(_buildSingleColumnOne(i));
}
return returnList;
}
//创建tableRows
List<TableRow> _buildTableRow() {
List<TableRow> returnList = new List();
for (int j = 0; j < 6; j++) {
returnList.add(_buildSingleRow(-1));//添加行
}
return returnList;
}
//创建单行
List<TableRow> _buildTableOneRow() {
List<TableRow> returnList = new List();
for (int j = 0; j < 1; j++) {
returnList.add(_buildSingleRow(-1));//添加行
}
return returnList;
}
//创建第一列tableRow
TableRow _buildSingleColumnOne(int index) {
return TableRow(
children: [
_buildSideBox(index == -1 ? '第一列' : "软件质量管理", index == -1),
_buildSideBox(index == -1 ? '第二列' : "软件质量管理", index == -1),
]);
}
//创建一行tableRow
TableRow _buildSingleRow(int index) {
return TableRow(
children: [
_buildSideBox(index == -1 ? '工作内容' : "学习", index == -1),
_buildSideBox(index == -1 ? '年度目标' : "成为顶尖开发", index == -1),
_buildSideBox(index == -1 ? '关联部门' : "1信息技术事业部", index == -1),
_buildSideBox(index == -1 ? '备注' : "不可能", index == -1),
_buildSideBox(index == -1 ? '1' : "随意添加", index == -1),
]);
}
//创建单个表格
Widget _buildSideBox(String title, isTitle) {
return SizedBox(
height: numRowHeight,
width: numRowWidth,
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(width: 0.33, color:Colors.black),
top: BorderSide(width: 0.33, color:Colors.black),
right: BorderSide(width: 0.33, color:Colors.black),
left: BorderSide(width: 0.33, color:Colors.black),
)
),
child: Text(
title,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: isTitle ? 14 : 12, color: Colors.black),
)));
}
@override
void initState() {
super.initState();
//监听第一列变动
firstColumnController.addListener(() {
if (firstColumnController.offset != thirdColumnController.offset) {
thirdColumnController.jumpTo(firstColumnController.offset);
}
});
//监听第三列变动
thirdColumnController.addListener(() {
if (firstColumnController.offset !=thirdColumnController.offset ) {
firstColumnController.jumpTo(thirdColumnController.offset);
}
});
//监听第一行变动
firstRowController.addListener(() {
if(firstRowController.offset !=secondedRowController.offset){
secondedRowController.jumpTo(firstRowController.offset);
}
});
//监听第二行变动
secondedRowController.addListener(() {
if(firstRowController.offset !=secondedRowController.offset){
firstRowController.jumpTo(secondedRowController.offset);
}
});
}
@override
Widget build(BuildContext context) {
return StatusBar(
color: Colors.white,
brightness: Brightness.dark,
child: Scaffold(
appBar: AppBar(
primary: false,
elevation: 0,
leading:Icon(Icons.arrow_back_ios),
title: Text('计划审批'),
), //SingleChildScrollView(
body: NotificationListener(
//表格
child: Container(
padding: EdgeInsets.only(right: 16,left:16,top: 16,bottom:0) ,
margin: EdgeInsets.only(right: 16,left:16),
height: 209,
width:375,
color:Colors.lightGreen,
child:Row(
children: [
//前两列
Container(
width:200,
height:200,
child:Column(
children: [
Table(
children: [
TableRow(
children:[
Container(
decoration: BoxDecoration(
border: Border(
top: BorderSide(width: 0.33, color:Colors.black),
right: BorderSide(width: 0.33, color:Colors.black),
left: BorderSide(width: 0.33, color:Colors.black),
),
),
child:SizedBox(
height:47,
child: Center(
child:Text('职责',textAlign: TextAlign.center),
),
),
),
Container(
// width:100,
decoration: BoxDecoration(
border: Border(
// bottom: BorderSide(width: 0.33, color:Colors.black),
top: BorderSide(width: 0.33, color:Colors.black),
right: BorderSide(width: 0.33, color:Colors.black),
left: BorderSide(width: 0.33, color:Colors.black),
),
),
child:SizedBox(
height:47,
child: Center(
child:Text('重点工作',textAlign: TextAlign.center),
),
),
)
],
),
],
),
//SingleChildScrollView(
Expanded(
child:
ListView(
controller: firstColumnController,
children: [
Table(
children: _buildTableColumnOne()
),
],
),
),
],
),
),
//其余列
Expanded(
child: Container(
width: 500,
child: Column(
children:[
SingleChildScrollView(
scrollDirection: Axis.horizontal,//horizontal
controller:firstRowController ,
child: Container(
child: Table(children: _buildTableOneRow()),
width: numRowWidth*6 ,//设置列的行宽
)
),
Expanded(
child:ListView(
controller: thirdColumnController,
children:[
SingleChildScrollView(
controller:secondedRowController ,
scrollDirection: Axis.horizontal,//horizontal
child: Row(
children:[
Container(
child: Table(children: _buildTableRow()),
width: numRowWidth*6 ,//设置列的行宽
)
],
),
),
],
),
),
]
),
),
),
],
),
),
),
),
);
}
}