用 Flutter 实现画板
迪丽瓦拉
2025-05-28 06:47:03
0次

本文作者为 360 奇舞团前端开发工程师

一、前期准备

可以按照flutter 官网搭建下相应的环境,这里大概讲解下用 fvm 搭建 flutter 环境。

MacOS 使⽤ fvm 管理多个 flutter 版本

  1. 安装fvm

    # 使用 brew 安装
    brew tap leoafarias/fvm
    brew install fvm
    # 使用 pub package 安装
    dart pub global activate fvm

    安装成功后命令行里会给出 fvm 目前安装路径 $PATH":"$HOME/.pub-cache/bin"

  2. 配置

    # .bash_profile 中添加
    export PATH = "$PATH":"$HOME/.pub-cache/bin"
    # 使.bash_profile 生效
    source .bash_profile
    # 执行 fvm 命令,看是否出现相关 help
  3. fvm 相关命令

  • 配置 fvm 缓存路径fvm config --cache-path

  • 查看当前安装的版本fvm list

  • 安装指定版本的 flutterfvm install version

  • 删除指定版本的 flutterfvm remove version

  • 指定当前使用哪个版本fvm use version

ps:切换 flutter 版本后需要敲下 fvm flutter doctor。因为每个版本不一样,所以可能需要重新下载运行环境

安装独立的 dart 环境

  1. 安装

brew tap dart-lang/dartbrew install dart
  1. 更新

brew upgrade dart
  1. 重新安装

brew reinstall dart

创建初始项目

fvm flutter create flutter_painter
cd flutter_painter
fvm flutter run

输入fvm flutter run后控制台会提示想选择用哪种设备进行调试,也可以使用flutter devices直接查询设备,flutter run -d all在所有设备上运行项目,我这里选择了用 web chrome 打开项目fvm flutter run -d Chrome。或者 mac 有 Xcode 的话,使用命令open -a Simulator可以直接打开 iOS 模拟器,然后执行flutter run,在执行前确保没有其他模拟器正在运行,这样项目就可以直接运行在 ios 模拟器上。ad2023dab36a3dc9050c012e81b10b92.png

二、了解 Path 与 CustomPainter

CustomPainter, 跟canvas一样,在 flutter 里我们可以用这个类绘制各种自定义图形。在这个类里我们需要实现 paint() 绘制方法与 shouldRepaint() 判断刷新布局的时是否需要重绘。

class SimplePainter extends CustomPainter {@overridevoid paint(Canvas canvas, Size size) {// 绘制代码Paint paint  = Paint()..color = Colors.black..style = PaintingStyle.stroke..strokeWidth = 5.0;Path path = Path();// 对路径进行相关操纵...path.close();canvas.drawPath(path, paint);}@overridebool shouldRepaint(CustomPainter oldDelegate) {return true}
}

具体的绘制由 canvas 画布和 paint 画笔来实现的。
canvas 相关方法:

方法功能
drawLine()画直线
drawCircle()画圆
drawOval()画椭圆
drawRect()画矩形
drawPoints()画点
drawArc()画圆弧

Paint 类参数:

属性名类型参考值功能
colorColorsColors.black画笔颜色
strokeWidthdouble5.0画笔粗细
strokeCapStrokeCapStrokeCap.round画笔笔触类型
isAntiAliasbooltrue是否启动抗锯齿

path 对象是需要绘制的元素集合,相关方法:

方法功能
moveTo()绘制的起点移到指定位置
lineTo()从起点绘制一条直线到指定位置
quadraticBezierTo()绘制二阶贝塞尔曲线
addRect()画矩形
addOval()画椭圆

实践

import 'package:flutter/material.dart';void main() {runApp(const MaterialApp(title: '画板', home: SafeArea(child: CanvasPage())));
}class CanvasPage extends StatefulWidget {const CanvasPage({Key? key}) : super(key: key);@overrideState createState() => _CanvasPageState();
}class _CanvasPageState extends State {Path path = Path();@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('画板')),body: Listener(// 落下onPointerDown: (e) {path.moveTo(e.localPosition.dx, e.localPosition.dy);setState(() {});},// 移动onPointerMove: (e) {path.lineTo(e.localPosition.dx, e.localPosition.dy);setState(() {});},// 离开onPointerUp: (e) {path.moveTo(e.localPosition.dx, e.localPosition.dy);path.close();setState(() {});},child: CustomPaint(foregroundPainter: CanvasPaint(path: path), child: Container(color: Colors.transparent))),);}
}class CanvasPaint extends CustomPainter {Path? path;Color? color; // 画笔颜色double? width;CanvasPaint({required this.path, this.color = Colors.black, this.width = 5});@overridevoid paint(Canvas canvas, Size size) {Paint paint = Paint()..color = color!..strokeWidth = width!..strokeCap = StrokeCap.round..style = PaintingStyle.stroke;canvas.drawPath(path!, paint);}// 是否需要重新绘制@overridebool shouldRepaint(covariant CanvasPaint oldDelegate) {// return oldDelegate.path != path;return true;}
}

三、部署到 chrome 插件

  1. 找到 web/index.html 文件并删除所有 标记:

30e6d7f7a9d7fc25a73f1bc67c4dbb81.png
  1. 在下插入

    1. 设置扩展程序尺寸,在 html 标签内添加宽高

    1. 在manifest.json中更改配置

    {"name": "flutter_painter_plugin","short_name": "flutter_painter_plugin","version": "1.0.0","content_security_policy": {"extension_pages": "script-src 'self'; object-src 'self'"},"action": {"default_popup": "index.html","default_icon": "icons/Icon-192.png"},"manifest_version": 3
    }
    1. 构建拓展程序,需要满足 csp 限制,生成的文件在build/web文件夹下

    fvm flutter build web --web-renderer html --csp
    1. 运行拓展程序

    (1)打开谷歌扩展程序页面

    chrome://extensions/

    (2) 选择开发者模式,选中加载已解压的扩展程序

    8af303c326f748c79b30b9c366111d30.png(3) 选择 build/web 文件夹,就可以看到新的扩展程序

    b7da0b895ab5b90cc70cfb3a1053fd22.pngd2705605b5eabffe181b79d753491038.gif

    参考资料

    谷歌扩展程序文档
    flutter 文档

    - END -

    关于奇舞团

    奇舞团是 360 集团最大的大前端团队,代表集团参与 W3C 和 ECMA 会员(TC39)工作。奇舞团非常重视人才培养,有工程师、讲师、翻译官、业务接口人、团队 Leader 等多种发展方向供员工选择,并辅以提供相应的技术力、专业力、通用力、领导力等培训课程。奇舞团以开放和求贤的心态欢迎各种优秀人才关注和加入奇舞团。

    e2f0ce2162dc61b92c8c410d8eb3b2f1.png

相关内容

热门资讯

“床车大军”只蹭厕所不住房,酒... ▲资料图:新能源汽车在某充换电站充电。多功能配置让新能源汽车成了可供休息的“床车”。图/新华社“自驾...
家国同框 | 假期里的韩家窝村 10月5日清晨,来到韩家窝村,此村坐落于淄博周村南郊镇,墨水河畔,三面环山,是省级传统古村落,国家3...
假期余额不足 成都市民近郊游享... 10月6日,距离国庆假期结束仅剩一天。成都阳光普照,在百仁公园里,草坪上满是天幕与帐篷。市民们在城区...
散客占比近八成,九寨沟迈入“散... 封面新闻记者 杨金祝九寨沟景区正进入散客时代。10月6日,记者从九寨沟景区获悉,国庆假期,九寨沟迎来...
黄金周 中国游 | “便利政策... 央视网消息:上海正全力打造“中国入境游第一站”,并推动入境游从赏景购物转向深度体验。在上海,外国游客...
通讯|布哈拉全城都知道中国放长...   新华社塔什干10月6日电 通讯|布哈拉全城都知道中国放长假了——探访中亚跨境旅游热  新华社记者...
奔县游|美食好物:小城烟火藏文...   眼下,以沉浸式、慢体验、近短途为特点的“奔县游”持续升温。地处江淮分水岭的安徽省来安县,立足半山...
专访丨约旦多措并举吸引中国游客... 新华社安曼10月6日电 专访|约旦多措并举吸引中国游客——访约旦旅游和文物大臣希贾津新华社记者何奕萍...
国庆别去外滩了,长宁才是隐藏款 国庆的上海,外滩是人山人海。但真正好逛的地方,不仅仅在最热闹的地界。长宁区延安西路1262号,上生·...
大渡河畔红色地标引游客 标题:赓续长征精神 奋进复兴征程|大渡河畔红色地标引游客国庆假期,各地游客来到位于四川省雅安市石棉县...