///数据模型
///派车次数统计 2
class SendCarNumberList {
List titleList = []; //派车次数统计
List sendCarList = []; //派车次数统计
int count1 = 0; //抽样
int count2 = 0; //还样
///派车次数统计 2
SendCarNumberList.fromMap2(Map map) {
if (map.isEmpty) return;
this.titleList = _getTitleList(map["data"]);
this.sendCarList = _getSendCarList(map["data"]);
}
///派车次数统计 2
List _getTitleList(Map map) {
List newList = List.from(map["titles"]);
return newList;
}
///派车次数统计 2
List _getSendCarList(Map map) {
List newList = [];
//CUM
SendCarNumberModel model1 = SendCarNumberModel.fromMap(map["CUM"]);
newList.add(model1);
//抽样-CUM
SendCarNumberModel model2 = SendCarNumberModel.fromMap(map["抽样"]["CUM"]);
newList.add(model2);
//抽样
List list2 = List.from(map["抽样"]["details"]);
this.count1 = list2.length;
list2.forEach((element) {
if (element is Map) {
newList.add(SendCarNumberModel.fromMap(element));
}
});
//还样-CUM
SendCarNumberModel model3 = SendCarNumberModel.fromMap(map["还样"]["CUM"]);
newList.add(model3);
//还样
List list3 = List.from(map["还样"]["details"]);
this.count2 = list3.length;
list3.forEach((element) {
if (element is Map) {
newList.add(SendCarNumberModel.fromMap(element));
}
});
return newList;
}
}
///派车次数统计 2
class SendCarNumberModel {
String a;
String b;
String c;
String d;
String e;
String f;
String g;
String h;
String i;
String j;
String k;
SendCarNumberModel({this.a, this.b, this.c, this.d, this.e, this.f, this.g, this.h, this.i, this.j, this.k});
SendCarNumberModel.fromMap(Map map) {
this.a = map["a"] != null ? map["a"].toString() : "";
this.b = map["b"] != null ? map["b"].toString() : "";
this.c = map["c"] != null ? map["c"].toString() : "";
this.d = map["d"] != null ? map["d"].toString() : "";
this.e = map["e"] != null ? map["e"].toString() : "";
this.f = map["f"] != null ? map["f"].toString() : "";
this.g = map["g"] != null ? map["g"].toString() : "";
this.h = map["h"] != null ? map["h"].toString() : "";
this.i = map["i"] != null ? map["i"].toString() : "";
this.j = map["j"] != null ? map["j"].toString() : "";
this.k = map["k"] != null ? map["k"].toString() : "";
}
List toList1() {
List list = [];
list.add(a);
list.add(b);
list.add(c);
return list;
}
List toList2() {
List list = [];
list.add(d);
list.add(e);
list.add(f);
list.add(g);
list.add(h);
list.add(i);
list.add(j);
list.add(k);
return list;
}
}
///派车次数统计 - 测试数据 2
var sendCarNumberTestData = {
"error": 0, //0:正常;1:异常
"message": "success", //正常:success;异常:fail具体异常描述
"count": 0,
"data": {
"titles": ["2022", "2021", "Jul", "Aug", "WK32", "WK31", "08/12", "08/11"],
"CUM": {
"a": "CUM", //派车
"b": "CUM", //始发
"c": "CUM", //接收
"d": "12956", //今年
"e": "12565", //上一年
"f": "126", //今月
"g": "125", //上一月
"h": "26", //今周
"i": "30", //上一周
"j": "10", //今天
"k": "6", //上一天
},
"抽样": {
"CUM": {
"a": "抽样", //派车
"b": "CUM", //始发
"c": "CUM", //接收
"d": "1295", //今年
"e": "1255", //上一年
"f": "12", //今月
"g": "15", //上一月
"h": "6", //今周
"i": "3", //上一周
"j": "1", //今天
"k": "2", //上一天
},
"details": [
{
"a": "抽样", //派车
"b": "C09V", //始发
"c": "G11", //接收
"d": "1256", //今年
"e": "1265", //上一年
"f": "16", //今月
"g": "15", //上一月
"h": "6", //今周
"i": "3", //上一周
"j": "1", //今天
"k": "6", //上一天
},
{
"a": "抽样", //派车
"b": "C06V", //始发
"c": "G112", //接收
"d": "1256", //今年
"e": "1265", //上一年
"f": "16", //今月
"g": "15", //上一月
"h": "6", //今周
"i": "3", //上一周
"j": "1", //今天
"k": "6", //上一天
},
{
"a": "抽样", //派车
"b": "C09V", //始发
"c": "G11", //接收
"d": "1256", //今年
"e": "1265", //上一年
"f": "16", //今月
"g": "15", //上一月
"h": "6", //今周
"i": "3", //上一周
"j": "1", //今天
"k": "6", //上一天
},
{
"a": "抽样", //派车
"b": "C06V", //始发
"c": "G112", //接收
"d": "1256", //今年
"e": "1265", //上一年
"f": "16", //今月
"g": "15", //上一月
"h": "6", //今周
"i": "3", //上一周
"j": "1", //今天
"k": "6", //上一天
},
],
},
"还样": {
"CUM": {
"a": "还样", //派车
"b": "CUM", //始发
"c": "CUM", //接收
"d": "1295", //今年
"e": "1255", //上一年
"f": "12", //今月
"g": "15", //上一月
"h": "6", //今周
"i": "3", //上一周
"j": "1", //今天
"k": "2", //上一天
},
"details": [
{
"a": "还样", //派车
"b": "C09V", //始发
"c": "G11", //接收
"d": "1256", //今年
"e": "1265", //上一年
"f": "16", //今月
"g": "15", //上一月
"h": "6", //今周
"i": "3", //上一周
"j": "1", //今天
"k": "6", //上一天
},
{
"a": "还样", //派车
"b": "C06V", //始发
"c": "G112", //接收
"d": "1256", //今年
"e": "1265", //上一年
"f": "16", //今月
"g": "15", //上一月
"h": "6", //今周
"i": "3", //上一周
"j": "1", //今天
"k": "6", //上一天
},
{
"a": "还样", //派车
"b": "C09V", //始发
"c": "G11", //接收
"d": "1256", //今年
"e": "1265", //上一年
"f": "16", //今月
"g": "15", //上一月
"h": "6", //今周
"i": "3", //上一周
"j": "1", //今天
"k": "6", //上一天
},
{
"a": "还样", //派车
"b": "C06V", //始发
"c": "G112", //接收
"d": "1256", //今年
"e": "1265", //上一年
"f": "16", //今月
"g": "15", //上一月
"h": "6", //今周
"i": "3", //上一周
"j": "1", //今天
"k": "6", //上一天
},
],
},
}
};
界面实现
import 'package:flutter/material.dart';
import 'package:flutter_table/tools/custom_calendar_widget.dart';
import 'package:flutter_table/tools/layout.dart';
import 'package:flutter_table/tools/logs.dart';
import 'package:flutter_table/tools/name_color_widget.dart';
import 'package:flutter_table/tools/public_widget.dart';
import 'package:linked_scroll_controller/linked_scroll_controller.dart';
import 'data_statistics_chart_model.dart';
///派車次數統計(次)3
class SendCarNumberPage extends StatefulWidget {
final String title; //派車次數統計
const SendCarNumberPage({Key key, @required this.title}) : super(key: key);
@override
State createState() => _SendCarNumberPageState();
}
///Chaos20200829
class _SendCarNumberPageState extends State {
//选择时间
String _selectTime = "";
//固定区域数据
List _fixedAreas = ["派车", "始发", "接收"];
//左边列表数据
List _leftList = [];
//右边标题数据
List _rightTitles = ["2022", "2021", "Jul", "Aug", "WK32", "WK31", "08/12", "08/11"];
//右边列表数据
List _rightList = [];
double _fixedAreaWidth = 150; //固定区域宽
double _fixedAreaHeight = 40; //固定区域高
double _itemWidth = 50; // item宽度
double _itemHeight = 40; // item长度
ScrollController _leftController; //左边数据-上下滚动控制器
ScrollController _rightTitleController; //右边标题-左右滚动控制器
ScrollController _rowController; //右边数据-左右滚动控制器
ScrollController _columnController; //右边数据-上下滚动控制器
LinkedScrollControllerGroup _verticalControllers; //垂直滚动同步
LinkedScrollControllerGroup _horizontalControllers; //水平滚动同步
int _count1 = 0; //抽样数据个数
int _count2 = 0; //还样数据个数
///init
@override
void initState() {
super.initState();
//现在的时间
_selectTime = DateTime.now().toString().split(".").first.split(" ").first;
//初始化控制器配置
_initController();
//数据
_getData();
}
///dispose
@override
void dispose() {
//销毁控制器
_disposeController();
super.dispose();
}
///build
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
height: w(50) + ((_rightList.length + 1) * w(40) + w(20) < w(385) ? (_rightList.length + 1) * w(40) + w(20) : w(385)),
color: Colors.white,
padding: EdgeInsets.symmetric(horizontal: w(16)),
child: Column(
children: [
_getTopWidget(widget.title, "images/iqc_sampling_sys/icon-data434.png"),
Expanded(child: _getForm()),
Container(height: w(20), color: Colors.white),
],
),
);
}
//界面..
///标题+时间选择 0
_getTopWidget(String title, String imagePath) {
return Container(
width: double.infinity,
height: w(50),
alignment: Alignment.center,
color: Colors.white,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
getTitle("$title(次)", Color(0xff000000), sp(18), fontWeight: FontWeight.bold),
_getTextImage(imagePath, _selectTime),
],
),
);
}
///时间选择 0
_getTextImage(String imagePath, String title) {
return InkWell(
onTap: () {
logs("选择时间...");
_showCalendar();
},
child: getTextImage(imagePath, title),
);
}
///弹窗-日历 0
_showCalendar() {
return showDialog(
context: context,
barrierColor: Color(0x66000000),
builder: (context) {
return Scaffold(
backgroundColor: Colors.transparent,
body: CustomCalendarWidget(
callBack: (value) {
//选择的时间
_selectTime = value.split(" ").first;
setState(() {});
},
),
);
});
}
///表格 1
_getForm() {
return Row(
children: [
//左边
_getLeftForm(),
//右边
Expanded(
child: _getRightForm(),
),
],
);
}
///左边表格 1.1
_getLeftForm() {
return Container(
width: _fixedAreaWidth,
child: Column(
children: [
//固定区域标题
Container(
width: _fixedAreaWidth,
height: _fixedAreaHeight,
child: _tabRowLeft(-1, _fixedAreas),
),
//左边-上下滑动区域
Expanded(
child: ListView.builder(
controller: _leftController,
scrollDirection: Axis.vertical, //垂直滚动
physics: BouncingScrollPhysics(),
padding: EdgeInsets.zero,
itemCount: _leftList.length,
itemBuilder: (context, index) {
return index == 0
? _tabRowCUM(0, _leftList[0].toList1()[2], 3)
: _tabRowLeft(index, _leftList[index].toList1(), isTitle: false);
},
),
),
],
),
);
}
///每行 1.1
_tabRowLeft(
int index, //下标
List data, //数组
{
bool isTitle = true,
}) {
var widget;
//始发=接收
if (data[1] == data[2]) {
widget = Row(
children: [
_tabRowCUM(index, "", 1),
_tabRowCUM(index, data[2], 2),
],
);
}
//始发!=接收
else {
widget = Row(
children: data.asMap().keys.map((i) {
String value = "";
if (i == 0) {
if (index == 1 + _count1 / 2 || index == 2 + _count1 + _count2 / 2) {
value = data[i];
} else if (index == -1) {
value = data[i];
}
} else {
value = data[i];
}
return Container(
width: w(50),
height: w(40),
alignment: Alignment.center,
decoration: BoxDecoration(
color: i == 0 ? Color(0xffc2d7ff) : Colors.transparent,
border: Border(
right: BorderSide(color: i == 7 ? Colors.transparent : Color.fromRGBO(255, 255, 255, 0.53), width: w(1)),
bottom: BorderSide(
color: index == 1 + _count1 && i == 0 ? Colors.white : Colors.transparent,
width: w(2),
),
),
),
child: Text(
value,
textAlign: TextAlign.center,
maxLines: 2,
style: TextStyle(fontSize: sp(16), color: isTitle ? Color(0xd6333333) : Color(0xff333333)),
),
);
}).toList(),
);
}
//返回
return Container(
decoration: BoxDecoration(
color: index == -1
? Color(0xffc2d7ff)
: index % 2 == 0
? Color.fromRGBO(236, 242, 250, 0.46)
: Color(0xffecf2fa),
),
child: widget,
);
}
///CUM 1.1
_tabRowCUM(int index, String value, int count) {
return Container(
width: w(50) * count,
height: w(40),
alignment: Alignment.center,
decoration: BoxDecoration(
color: count == 3
? Color.fromRGBO(236, 242, 250, 0.46)
: value.isEmpty
? Color(0xffc2d7ff)
: index % 2 == 0
? Colors.transparent
: Color(0xffecf2fa),
border: Border(
right: BorderSide(color: Color.fromRGBO(255, 255, 255, 0.53), width: w(1)),
),
),
child: Text(
value,
textAlign: TextAlign.center,
maxLines: 2,
style: TextStyle(fontSize: sp(16), color: Color(0xff333333)),
),
);
}
///右边表格 1.2
_getRightForm() {
return Column(
children: [
//右边标题-左右滚动区域
Container(
width: _itemWidth * _rightTitles.length,
height: _itemHeight,
child: ListView.builder(
controller: _rightTitleController,
scrollDirection: Axis.horizontal, //水平滚动
physics: BouncingScrollPhysics(),
padding: EdgeInsets.zero,
itemCount: _rightTitles.length,
itemBuilder: (context, index) {
return _tabItemRight(index, _rightTitles[index]);
},
),
),
//右边-上下-左右-滚动区域
Expanded(
child: ListView(
controller: _rowController,
scrollDirection: Axis.horizontal, //水平滚动
physics: BouncingScrollPhysics(),
padding: EdgeInsets.zero,
children: [
Container(
width: _itemWidth * _rightList[0].toList2().length,
child: ListView.builder(
controller: _columnController,
scrollDirection: Axis.vertical, //垂直滚动
physics: BouncingScrollPhysics(),
padding: EdgeInsets.zero,
itemCount: _rightList.length,
itemBuilder: (context, index) {
return _tabRowRight(index, _rightList[index].toList2(), isTitle: false);
},
),
)
],
),
),
],
);
}
///每行 1.2
_tabRowRight(
int index, //下标
List data, //数组
{
bool isTitle = true,
}) {
return Container(
decoration: BoxDecoration(
color: index == -1
? Color(0xffc2d7ff)
: index % 2 == 0
? Color.fromRGBO(236, 242, 250, 0.46)
: Color(0xffecf2fa),
),
child: Row(
children: data.asMap().keys.map((i) {
return Container(
width: w(50),
height: w(40),
alignment: Alignment.center,
decoration: BoxDecoration(
border: Border(
right: BorderSide(color: i == 7 ? Colors.transparent : Color.fromRGBO(255, 255, 255, 0.53), width: w(1)),
),
),
child: Text(
data[i].toString(),
textAlign: TextAlign.center,
maxLines: 2,
style: TextStyle(fontSize: sp(16), color: isTitle ? Color(0xd6333333) : Color(0xff333333)),
),
);
}).toList(),
),
);
}
///每个 1.2
_tabItemRight(
int i, //下标
String value, //值
{
bool isTitle = true,
}) {
return Container(
width: w(50),
height: w(40),
alignment: Alignment.center,
decoration: BoxDecoration(
color: Color(0xffc2d7ff),
border: Border(
right: BorderSide(color: i == 7 ? Colors.transparent : Color.fromRGBO(255, 255, 255, 0.53), width: w(1)),
),
),
child: Text(
value.toString(),
textAlign: TextAlign.center,
maxLines: 2,
style: TextStyle(fontSize: sp(16), color: isTitle ? Color(0xd6333333) : Color(0xff333333)),
),
);
}
//事件..
///初始化控制器配置
_initController() {
_fixedAreaWidth = w(150); //固定区域宽
_fixedAreaHeight = w(40); //固定区域高
_itemWidth = w(50); // item宽度
_itemHeight = w(40); // item高度
//水平滚动同步
_horizontalControllers = LinkedScrollControllerGroup();
_rightTitleController = _horizontalControllers?.addAndGet();
_rowController = _horizontalControllers?.addAndGet();
//垂直滚动同步
_verticalControllers = LinkedScrollControllerGroup();
_leftController = _verticalControllers?.addAndGet();
_columnController = _verticalControllers?.addAndGet();
}
///销毁控制器
_disposeController() {
_leftController?.dispose();
_rightTitleController?.dispose();
_rowController?.dispose();
_columnController?.dispose();
}
//数据...
///数据
_getData() {
SendCarNumberList model = SendCarNumberList.fromMap2(sendCarNumberTestData);
_leftList = model.sendCarList;
_rightTitles = model.titleList;
_rightList = model.sendCarList;
_count1 = model.count1;
_count2 = model.count2;
}
}
linked_scroll_controller: ^0.2.0 #引入列表同步滚动
import 'package:flutter/material.dart';
import 'package:linked_scroll_controller/linked_scroll_controller.dart';
//固定标题的滑动
class TimeTablePage extends StatefulWidget {
const TimeTablePage({Key key}) : super(key: key);
@override
_TimeTablePageState createState() => _TimeTablePageState();
}
class _TimeTablePageState extends State {
int rowsCount = 100; //左边标题的个数
int columnsCount = 30; //右边标题的个数
double cellWidth = 80; // item宽度
double cellHeight = 50; // item长度
ScrollController leftController; //左边标题
ScrollController topController; //右边标题
ScrollController rowController; //数据
List columnsController = [];
LinkedScrollControllerGroup _verticalControllers;
LinkedScrollControllerGroup _horizontalControllers;
///init
@override
void initState() {
super.initState();
//初始化控制器配置
_initController();
}
///dispose
@override
void dispose() {
//销毁控制器
_disposeController();
super.dispose();
}
///build
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("工时表"),
),
body: _bodyWidget(),
);
}
//界面...
///表格
_bodyWidget() {
return Row(
children: [
//左边
Container(
width: cellWidth,
child: Column(
children: [
//时间 姓名
Container(
decoration: BoxDecoration(
color: Colors.blueGrey[100],
border: Border.all(color: Color(0xffeeeeee), width: 1),
),
padding: EdgeInsets.only(left: 5.0, right: 5.0),
height: cellHeight,
width: cellWidth,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
alignment: Alignment.topRight,
child: Text("时间"),
),
Container(alignment: Alignment.bottomLeft, child: Text("姓名"))
],
),
),
//左边的标题
Expanded(
child: ListView.builder(
controller: leftController,
scrollDirection: Axis.vertical,
padding: EdgeInsets.all(0),
itemBuilder: (context, index) {
return Container(
decoration: BoxDecoration(
color: Colors.blueGrey[100],
border: Border.all(color: Color(0xffeeeeee), width: 1),
),
height: cellHeight,
child: Center(child: Text("张${index + 1}")));
},
itemCount: rowsCount - 1,
),
),
],
),
),
//右边
Expanded(
child: Column(
children: [
//右边标题
Container(
height: cellHeight,
child: ListView.builder(
controller: topController,
padding: EdgeInsets.all(0),
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return Container(
decoration: BoxDecoration(
color: Colors.blueGrey[100],
border: Border.all(color: Color(0xffeeeeee), width: 1),
),
width: cellWidth,
child: Center(child: Text("8月${index + 1}日")));
},
itemCount: columnsCount,
),
),
//右边数据
Expanded(
child: ListView.builder(
controller: rowController,
padding: EdgeInsets.all(0),
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return Container(
width: cellWidth,
child: ListView.builder(
controller: columnsController[index],
scrollDirection: Axis.vertical,
shrinkWrap: true,
padding: EdgeInsets.all(0),
itemBuilder: (context, innerIndex) {
return Container(height: cellHeight, child: Center(child: Text("$innerIndex, $index")));
},
itemCount: rowsCount - 1,
),
);
},
itemCount: columnsCount,
),
)
],
),
),
],
);
}
//事件...
///初始化控制器配置
_initController() {
//水平同步滚动
_horizontalControllers = LinkedScrollControllerGroup();
topController = _horizontalControllers?.addAndGet();
rowController = _horizontalControllers?.addAndGet();
//垂直同步滚动
_verticalControllers = LinkedScrollControllerGroup();
leftController = _verticalControllers?.addAndGet();
for (var i = 0; i < columnsCount; i++) {
ScrollController columnController = _verticalControllers?.addAndGet();
if (columnController != null) {
columnsController.add(columnController);
}
}
}
///销毁控制器
_disposeController() {
leftController?.dispose();
topController?.dispose();
rowController?.dispose();
for (var controller in columnsController) {
controller.dispose();
}
}
}
参考:
https://www.jianshu.com/p/1543c5fda631