Flutter---坐标网格图标

效果图

Flutter本身没有直接绘制虚线的内置组件,所以需要自定义画虚线的工具类

Dart 复制代码
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像素
  });

  @override
  void 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;
    }
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}

使用方式

Dart 复制代码
           Positioned( //确定位置
            left: 280 / 4,//水平位置
            child: CustomPaint(//设置画布
              size: Size(0.5, 215), // 宽度0.5,高度215
              painter: DashPainter(
                color: Color(0xFF878787),
                strokeWidth: 0.5,//线条粗细
                dashWidth: 3,//每段虚线长度
                dashSpace: 2,//虚线间隔
              ),
            ),
          ),

数据流

Dart 复制代码
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. 结果显示在屏幕上

代码实例

Dart 复制代码
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});

  @override
  State<StatefulWidget> createState() => _HomePageState();

}

class _HomePageState extends State<HomePage>{

  //UI构建
  @override
  Widget 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,高度215
              painter: 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,
              ),
            ),
          ),
    ],
    ),
    );
  }
}
相关推荐
用户21411832636024 小时前
假期值班,困在形式主义里的“假坚守”
前端
Chloe_lll4 小时前
threejs(五)纹理贴图、顶点UV坐标
javascript·贴图·uv
zhifanxu4 小时前
flutter布局调试
flutter
需要兼职养活自己4 小时前
react【portals】与vue3【<Teleport>】
前端·react.js
用户47949283569154 小时前
React 19.2 重磅更新:终于解决 useEffect 依赖数组难题
前端·react.js
梦里小白龙4 小时前
前端视频课程添加水印,全屏不消失解决方法
前端·音视频
我命由我123454 小时前
PDFBox - PDDocument 与 byte 数组、PDF 加密
java·服务器·前端·后端·学习·java-ee·pdf
@PHARAOH4 小时前
HOW - prefetch 二级页面实践
前端·javascript·react.js
EF@蛐蛐堂4 小时前
WUJIE VS QIANKUN 微前端框架选型(一)
前端·vue.js·微服务·架构