原文链接:Creating a Drawing Canvas in Flutter - 原文作者 Zaki
本文采用意译的方式
在 Flutter
中创建绘图应用程序是一个有益的过程,可以将用户交互和图像渲染相结合。在本文,我们将手把手构建一个简单的绘图画布,在画布上用户可以在画布上使用手指自由绘画并选择不同颜色的画笔。
最终效果
步骤一:设置 Flutter 环境
在开始编码前,我们需要确保自己系统上安装了 Flutter
。我们可以从 Flutter 官方站点下载并安装 Flutter
。
步骤二:创建一个新的 Flutter 项目
打开我们的终端,然后跑下面的命令行来创建一个新的 Flutter
项目:
bash
flutter create drawing_app
导航到我们项目目录:
bash
cd drawing_app
步骤三:添加依赖
对于我们 drawing_app
项目,我们需要 flutter_colorpicker
包,以允许用户来挑选颜色。在 pubspec.yaml
的属性 dependencies
下添加下面内容:
yaml
dependencies:
flutter:
sdk: flutter
flutter_colorpicker: any
运行 flutter pub get
来安装新的依赖。
步骤四:主要应用入口
打开 main.dart
文件,然后设置程序的主要入口:
dart
import 'package:flutter/material.dart';
import 'package:flutter_colorpicker/flutter_colorpicker.dart'
void main() => runApp(MyApp());
步骤五:创建 MyApp 挂件
定义 MyApp
关键,它将主页设置在 MaterialApp
中:
dart
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Drawing App',
home: DrawingPage(),
);
}
}
步骤六:设置 DrawingPage 挂件
创建有状态的挂件 DrawingPage
,在那里绘制画布:
dart
class DrawingPage extends StatefulWidget {
const DrawingPage({super.key});
@override
_DrawingPageState createState() => _DrawingPageState();
}
步骤七:管理绘制状态
在 _DrawingPageState
中,管理绘制点,选定颜色和描边宽度的状态:
dart
class _DrawingPageState extends State<DrawingPage> {
List<DrawingPoints> points = [];
Color selectedColor = Colors.black;
double strokeWidth = 4.0;
List<Color> colorOptions = [
Colors.black,
Colors.red,
Colors.green,
Colors.blue,
Colors.yellow,
Colors.purple,
Colors.orange,
Colors.brown,
]; // 自定义颜色列表
步骤八:构建 UI
定义一个 AppBar
来进行控制,和 GestureDetector
来处理绘制手势:
dart
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Draw on Canvas"),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.clear),
onPressed: () => setState(() => points.clear()),
),
IconButton(
icon: const Icon(Icons.color_lens),
onPressed: pickColor,
),
],
),
body: GestureDetector(
onPanUpdate: (details) {
RenderBox? renderBox = context.findRenderObject() as RenderBox?;
if (renderBox != null) {
setState(() {
points.add(
DrawingPoints(
points: renderBox.globalToLocal(details.localPosition),
paint: Paint()
..strokeCap = StrokeCap.round
..isAntiAlias = true
..color = selectedColor
..strokeWidth = strokeWidth,
isPoint: true,
),
);
});
}
},
onPanEnd: (details) {
setState(() {
points.add(DrawingPoints(
points: Offset.zero, paint: Paint(), isPoint: false));
});
},
child: CustomPaint(
painter: DrawingPainter(points: points),
child: Container(),
),
),
);
}
步骤九:处理颜色变更
实现 pickerColor
来显示颜色拾取器,以允许用户更改画笔的颜色:
dart
void pickColor() {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Choose a color'),
content: SingleChildScrollView(
child: BlockPicker(
pickerColor: selectedColor,
availableColors: colorOptions, // 在这使用自定义颜色列表
onColorChanged: changeColor,
),
),
actions: <Widget>[
TextButton(
child: const Text('Close'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
void changeColor(Color color) {
Navigator.of(context).pop(); // 关闭对话框
setState(() {
selectedColor = color;
});
}
}
步骤十:实现绘制逻辑
使用 CustomPainter
来处理真实的绘制逻辑:
dart
class DrawingPoints {
Paint paint;
Offset points;
bool isPoint;
DrawingPoints({
required this.points,
required this.paint,
this.isPoint = true,
});
}
class DrawingPainter extends CustomPainter {
List<DrawingPoints> points;
DrawingPainter({required this.points});
@override
void paint(Canvas canvas, Size size) {
for (int i = 0; i < points.length - 1; i++) {
if (points[i].isPoint &&
points[i + 1].isPoint) {
canvas.drawLine(
points[i].points, points[i + 1].points, points[i].paint);
}
}
}
@override
bool shouldRepaint(covariant DrawingPainter oldDelegate) => true;
}
类: DrawingPoints
目的:在画布中展示单个点。
字段:
Offset points
:表示点在画布上的坐标。Paint paint
:指定此点要使用的绘画风格(颜色、绘制等)。bool isPoint
:布尔值,决定是否应该将对象视为绘制的点。这可能用于根据上下文或者触摸交互类型以不同方式处理触摸事件(例如,绘制一个点而不是一条线)。Constructor
:明确需要提供的points
和paint
。除非指定,否则isPoints
默认是true
。
类: DrawingPainter
目的:自定义画家类是基于 DrawingPoints
列表在画布上绘图。
字段:
List<DrawingPoints> points
:DrawingPoints
列表定义我们想要在画布上绘制的点。Constructor
:初始化points
列表数据。- 方法:
paint(Canvas canvas, Size size)
:当挂件需要重绘时候调用。如果当前点和下一个点标记为可绘制(isPoint
为真),此方法遍历列表并从每个点到下一个点绘制一条线。- 它使用
Canvas
对象中的drawLine
方法,使用DrawingPoints
中指定的绘制样式在连续点之间进行连线。 shouldRepaint(covariant DrawingPainter oldDelegate)
:总是返回true
,表明每次都要更新绘画。如果点列表不频繁更改,这不是性能最优的选择,因为即使没有必要也会重新绘制。
paint 方法的逻辑
paint
方法的逻辑本质上是在连续的点之间绘线,这些点应该是 isPoint
为 true
的点。如果点不是连续的,即 isPoint
为 false
,则跳过绘制到下一个点。这是处理用户手指抬离屏幕然后触屏生成另一个点绘制不连续点的简单方法。
步骤十一:测试应用
在终端上运行 flutter run
来运行我们的程序,或者使用 IDE
的运行按钮。我们应该可以在屏幕上绘制并且更改画笔🖌️的颜色。
总结
现在,我们使用 Flutter
成功地创建了一个基础的绘图应用!这个应用允许我们在屏幕上选择颜色来绘制,并且清空绘制。我们可以通过添加更多的特性来扩展,比如调整画笔的大小,保存绘图或者添加更加复杂的手势。
这个教程为在 Flutter
中创建交互式图形应用程序提供了坚实的基础。尝试更多的功能并自定义来扩展我们应用程序的能力。