Flutter---坐标网格图标
效果图
Flutter本身没有直接绘制虚线的内置组件,所以需要自定义画虚线的工具类
import 'package:flutter/material.dart';//绘制垂直虚线的工具类
class DashPainter extends CustomPainter {//1.定义常量final Color color;final double strokeWidth;final double dashWidth;final double dashSpace;//2.构造函数DashPainter({this.color = Colors.black, //虚线颜色,默认黑色this.strokeWidth = 1.0, //线宽,默认1像素this.dashWidth = 3.0,//每个短划的长度,默认3像素this.dashSpace = 2.0,//短滑之间的距离,默认2像素});@overridevoid paint(Canvas canvas, Size size) { //size(215)来自CustomPaint的size属性,size由Flutter自动传入//3.创建画笔final paint = Paint()..color = color//设置颜色..strokeWidth = strokeWidth//设置线宽..style = PaintingStyle.stroke;//设置为描边模式// 4.计算x坐标,让线条在容器中居中final x = strokeWidth / 2;double startY = 0;//起始Y坐标//5.循环直到画满整个高度while (startY < size.height) {//绘制一个短划canvas.drawLine(Offset(x, startY), //起点坐标,X坐标固定,Y变化,所以是绘制垂直线Offset(x, startY + dashWidth),//终点坐标,X坐标固定,Y变化,所以是绘制垂直线paint,//使用的画笔);//移动到下一个短划的起始位置startY += dashWidth + dashSpace;}}@overridebool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}
使用方式
Positioned( //确定位置left: 280 / 4,//水平位置child: CustomPaint(//设置画布size: Size(0.5, 215), // 宽度0.5,高度215painter: DashPainter(color: Color(0xFF878787),strokeWidth: 0.5,//线条粗细dashWidth: 3,//每段虚线长度dashSpace: 2,//虚线间隔),),),
数据流
Positioned → CustomPaint → DashPainter构造函数 → paint方法 → 绘制到屏幕↓ ↓ ↓ ↓ ↓
位置定位 设置画布大小 接收绘制参数 执行绘制逻辑 显示虚线
①Positioned定位:left = 70
②CustomPaint设置画布,画布大小:宽0.5px,高215px
③DashPainter 构造函数接收参数
④paint 方法拿到参数,创建画笔和计算参数: x = 0.5 ÷ 2 = 0.25(居中位置),Y默认为0
⑤执行循环划线的方法,直到Y大于215
⑥虚线画完,显示在屏幕上
完整调用栈
1. Flutter框架构建Positioned
2. Positioned创建CustomPaint
3. CustomPaint创建DashPainter实例
4. DashPainter构造函数保存参数
5. Flutter调用DashPainter.paint()
6. paint()方法执行绘制循环
7. 43次canvas.drawLine()调用
8. 结果显示在屏幕上
代码实例
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:my_flutter/dash_painter.dart';class HomePage extends StatefulWidget{const HomePage({super.key});@overrideState<StatefulWidget> createState() => _HomePageState();}class _HomePageState extends State<HomePage>{//UI构建@overrideWidget build(BuildContext context) {return Scaffold(body: Padding(padding: EdgeInsets.only(left: 20,top: 200),//内边距child: Column(crossAxisAlignment: CrossAxisAlignment.start,children: [// Y轴坐标标签和表格行Row(crossAxisAlignment: CrossAxisAlignment.start,children: [// Y轴标签(左侧)Container(width: 20,height: 215,child: Column(mainAxisAlignment: MainAxisAlignment.spaceBetween,children: [Text('180', style: TextStyle(fontSize: 10)),Text('120', style: TextStyle(fontSize: 10)),Text('60', style: TextStyle(fontSize: 10)),Text('0', style: TextStyle(fontSize: 10)),],),),// 表格主体_buildTodayTable(),],),// X轴坐标标签(底部)Container(padding: EdgeInsets.only(left: 20, right: 45),width: 305,child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween,children: [Text("0时", style: TextStyle(fontSize: 10)),Text("6时", style: TextStyle(fontSize: 10)),Text("12时", style: TextStyle(fontSize: 10)),Text("18时", style: TextStyle(fontSize: 10)),],),),],),),);}//表格的主体Widget _buildTodayTable() {return Container(width: 280,height: 215,decoration: BoxDecoration(//边框border: Border(left: BorderSide(color: Color(0xFF878787), width: 0.5),right: BorderSide(color: Color(0xFF878787), width: 0.5),bottom: BorderSide(color: Color(0xFF878787), width: 0.5),top: BorderSide(color: Color(0xFF878787), width: 0.5),),),child: Stack(children: [// 第一条中间水平线Positioned(top: 215 / 3,child: Container(width: 305,height: 0.5,color: Color(0xFF878787),),),// 第二条中间水平线Positioned(top: 215 * 2 / 3,child: Container(width: 305,height: 0.5,color: Color(0xFF878787),),),// 垂直线(全虚线)Positioned( //确定位置left: 280 / 4,//水平位置child: CustomPaint(//设置画布size: Size(0.5, 215), // 宽度0.5,高度215painter: DashPainter(color: Color(0xFF878787),strokeWidth: 0.5,//线条粗细dashWidth: 3,//每段虚线长度dashSpace: 2,//虚线间隔),),),Positioned(left: 280 / 2,child: CustomPaint(size: Size(0.5, 215),painter: DashPainter(color: Color(0xFF878787),strokeWidth: 0.5,dashWidth: 3,dashSpace: 2,),),),Positioned(left: 280 * 3 / 4,child: CustomPaint(size: Size(0.5, 215),painter: DashPainter(color: Color(0xFF878787),strokeWidth: 0.5,dashWidth: 3,dashSpace: 2,),),),],),);}
}