自定义一个柱状图
[图片上传失败...(image-9a235c-1691401253525)]
import 'package:flutter/material.dart';
import 'dotted_dashed_line.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<ListColumn> list = [
ListColumn("周一", [
ColumnItem(0, Colors.green),
ColumnItem(0, Colors.red),
ColumnItem(0, Colors.blue)
]),
ListColumn("周二", [
ColumnItem(0, Colors.green),
ColumnItem(0, Colors.red),
ColumnItem(0, Colors.blue)
]),
ListColumn(
"周三",
[
ColumnItem(0, Colors.green),
ColumnItem(0, Colors.red),
ColumnItem(0, Colors.blue)
],
),
ListColumn(
"周四",
[
ColumnItem(0, Colors.green),
ColumnItem(0, Colors.red),
ColumnItem(0, Colors.blue)
],
),
ListColumn("周五", [
ColumnItem(0, Colors.green),
ColumnItem(0, Colors.red),
ColumnItem(0, Colors.blue)
]),
ListColumn(
"周六",
[
ColumnItem(0, Colors.green),
ColumnItem(0, Colors.red),
ColumnItem(0, Colors.blue)
],
),
ListColumn("周日", [
ColumnItem(0, Colors.green),
ColumnItem(0, Colors.red),
ColumnItem(0, Colors.blue)
])
];
@override
void initState() {
super.initState();
Future.delayed(const Duration(seconds: 4), () {
list = [
ListColumn("周一", [
ColumnItem(20, Colors.green),
ColumnItem(10, Colors.red),
ColumnItem(20, Colors.blue)
]),
ListColumn("周二", [
ColumnItem(50, Colors.green),
ColumnItem(60, Colors.red),
ColumnItem(20, Colors.blue)
]),
ListColumn(
"周三",
[
ColumnItem(40, Colors.green),
ColumnItem(30, Colors.red),
ColumnItem(10, Colors.blue)
],
),
ListColumn(
"周四",
[
ColumnItem(60, Colors.green),
ColumnItem(10, Colors.red),
ColumnItem(20, Colors.blue)
],
),
ListColumn("周五", [
ColumnItem(15, Colors.green),
ColumnItem(15, Colors.red),
ColumnItem(5, Colors.blue)
]),
ListColumn(
"周六",
[
ColumnItem(40, Colors.green),
ColumnItem(12, Colors.red),
ColumnItem(8, Colors.blue)
],
),
ListColumn("周日", [
ColumnItem(22, Colors.green),
ColumnItem(13, Colors.red),
ColumnItem(16, Colors.blue)
])
];
setState(() {});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title)),
body: HistogramWidget(height: 300, list: list));
}
}
class HistogramWidget extends StatefulWidget {
final double height;
final List<ListColumn> list;
const HistogramWidget({required this.height, required this.list, super.key});
@override
State<HistogramWidget> createState() => _HistogramWidgetState();
}
class _HistogramWidgetState extends State<HistogramWidget> {
double px = 1;
///误差线
List<int> lines = [];
///获取数组最大数
double findMax(List<double> numbers) {
if (numbers.isEmpty) {
return 0;
}
double max = numbers[0];
for (double number in numbers) {
if (number > max) {
max = number;
}
}
return max;
}
///获取误差线
List<int> calculateNodes(double inputNumber) {
var item = nearestMultipleOf5(nearestMultipleOf5(inputNumber ~/ 2) ~/ 2);
return [0, item, item * 2, item * 3, item * 4];
}
///获取就近 大于当前的5的倍数
int nearestMultipleOf5(int number) {
int nextMultiple = ((number ~/ 5) + 1) * 5;
return nextMultiple;
}
@override
Widget build(BuildContext context) {
///获取比例
List<double> ints = [];
for (var element in widget.list) {
double total = 0;
for (var element in element.list) {
total += element.value;
}
ints.add(total);
}
///获取最大数
double max = findMax(ints);
if (max == 0) {
max = 100;
}
///获取误差线
lines = calculateNodes(max);
px = widget.height / lines[lines.length - 1];
return SizedBox(
height: (widget.height + 40),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Expanded(child: Stack(fit: StackFit.expand, children: getLines()))
]));
}
getColumnChildren() {
List<Widget> children = [];
for (var element in widget.list) {
children.add(ColumnWidget(listColumn: element, px: px));
}
return children;
}
List<Widget> getLines() {
List<Widget> lis = [];
for (var element in lines) {
lis.add(Positioned(
bottom: element * px,
left: 0,
right: 0,
child: XLine(title: "$element")));
}
lis.add(Align(
alignment: Alignment.bottomCenter,
child: AnimatedContainer(
padding: const EdgeInsets.only(left: 30, right: 10),
duration: const Duration(seconds: 1),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.end,
children: getColumnChildren()))));
return lis;
}
}
class ColumnWidget extends StatelessWidget {
final ListColumn listColumn;
final double px;
const ColumnWidget({required this.listColumn, required this.px, super.key});
@override
Widget build(BuildContext context) {
return Transform.translate(
offset: const Offset(0, 20),
child: Column(
children: [
Expanded(
child: Align(
alignment: Alignment.bottomCenter,
child: Column(
mainAxisSize: MainAxisSize.min,
children: getChildren(listColumn.list),
))),
SizedBox(
height: 20,
child: Center(
child: Text(listColumn.title,
style: const TextStyle(color: Colors.red))))
],
),
);
}
List<Widget> getChildren(List<ColumnItem> listValue) {
List<Widget> children = [];
for (int i = 0; i < listValue.length; i++) {
children.add(AnimatedContainer(
width: 21,
height: listValue[i].value * px,
decoration: BoxDecoration(
borderRadius: i == 0
? const BorderRadius.only(
topLeft: Radius.circular(3), topRight: Radius.circular(3))
: null,
color: listValue[i].color),
duration: const Duration(seconds: 1),
));
}
return children;
}
}
class ListColumn {
final String title;
final List<ColumnItem> list;
const ListColumn(this.title, this.list);
}
class ColumnItem {
final double value;
final Color color;
ColumnItem(this.value, this.color);
}
class XLine extends StatelessWidget {
final String title;
const XLine({required this.title, super.key});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title),
const DottedDashedLine(
height: 1, width: double.infinity, axis: Axis.horizontal)
],
);
}
}
网友评论