介紹 :
在Flutter中,所有內(nèi)容都圍繞Widget。Flutter讓你靈活創(chuàng)建一些漂亮的UI小部件,并且該應(yīng)用程序可以在iOS和Android上使用。因此,將您創(chuàng)建的這些小部件繪制到移動(dòng)屏幕上,或者我們可以將其稱為繪制在畫布上(Canvas)。那么我們也可以將其用作繪圖板來(lái)繪圖。

我們將使用custom painter在畫布上繪畫,我們將提供更改畫筆的大小,不透明度和顏色的選項(xiàng)。
該代碼位于https://github.com/sharansingh00002/draw
現(xiàn)在讓我們來(lái)看看這是如何完成的:)
Code Time
我們需要具備的第一個(gè)信息是用戶與之交互的畫布上的點(diǎn)的坐標(biāo),我們可以使用Gesture Detector輕松獲得該信息。我們將使用手勢(shì)檢測(cè)器的onPanUpdate,onPanStart和onPanEnd屬性。當(dāng)用戶單擊屏幕時(shí)使用onPanStart,這樣我們可以繪制一個(gè)點(diǎn),但是如果用戶拖動(dòng),則使用onPanUpdate可以獲取連續(xù)點(diǎn),并且OnPanEnd通知用戶已停止繪制。
我們將這些點(diǎn)存儲(chǔ)在列表中,其中每個(gè)元素將具有坐標(biāo)以及與該點(diǎn)關(guān)聯(lián)的繪制屬性。
class DrawingPoints {
Paint paint;
Offset points;
DrawingPoints({this.points, this.paint});
}
在手勢(shì)檢測(cè)器中,onPanUpdate函數(shù)看起來(lái)像
onPanUpdate: (details) {
setState(() {
RenderBox renderBox = context.findRenderObject();
points.add(DrawingPoints(
points: renderBox.globalToLocal(details.globalPosition),
paint: Paint()
..strokeCap = strokeCap
..isAntiAlias = true
..color = selectedColor.withOpacity(opacity)
..strokeWidth = strokeWidth));
});
},
onPanStart: (details) {
setState(() {
RenderBox renderBox = context.findRenderObject();
points.add(DrawingPoints(
points: renderBox.globalToLocal(details.globalPosition),
paint: Paint()
..strokeCap = strokeCap
..isAntiAlias = true
..color = selectedColor.withOpacity(opacity)
..strokeWidth = strokeWidth));
});
},
onPanEnd: (details) {
setState(() {
points.add(null);
});
},
因此,我們使用渲染框獲取要在其上進(jìn)行繪制的渲染對(duì)象,并將該框的全局坐標(biāo)系點(diǎn)轉(zhuǎn)換為局部坐標(biāo)系。我們將在末尾添加null以標(biāo)記繪圖的結(jié)束。
現(xiàn)在讓我們看一下自定義的CustomPainter類,該類負(fù)責(zé)在屏幕上繪制。
class DrawingPainter extends CustomPainter {
DrawingPainter({this.pointsList});
List<DrawingPoints> pointsList;
List<Offset> offsetPoints = List();
@override
void paint(Canvas canvas, Size size) {
for (int i = 0; i < pointsList.length - 1; i++) {
if (pointsList[i] != null && pointsList[i + 1] != null) {
canvas.drawLine(pointsList[i].points, pointsList[i +1].points ,
pointsList[i].paint);
} else if (pointsList[i] != null && pointsList[i + 1] == null) {
offsetPoints.clear();
offsetPoints.add(pointsList[i].points);
offsetPoints.add(Offset(
pointsList[i].points.dx + 0.1, pointsList[i].points.dy + 0.1));
canvas.drawPoints(PointMode.points, offsetPoints, pointsList[i].paint);
}
}
}
@override
bool shouldRepaint(DrawingPainter oldDelegate) => oldDelegate.pointsList!=pointsList;
}
我們使用Canvas.drawLine函數(shù)繪制線條,但是如果用戶剛剛在屏幕上輕擊,則使用Canvas.drawPoint繪制該點(diǎn)。
我們正在檢查是否為null,因?yàn)樵谟脩敉V估L圖時(shí)我們將添加null,以便如果他再次開始繪圖,則最后一個(gè)繪圖的最后一點(diǎn)和新繪圖的起點(diǎn)不應(yīng)該連接。
要清除屏幕,只需清除pointsList。
定制:
因此,我們可以添加許多自定義項(xiàng),到目前為止,我已經(jīng)添加了更改筆觸寬度,筆刷的不透明度和顏色的選項(xiàng)。
因此,對(duì)于strokeWidth和不透明度Opacity,我們可以簡(jiǎn)單地使用Slider來(lái)更改值,對(duì)于Color,我們提供一些預(yù)定義的最常用的顏色,以及使用顏色選擇器選擇其選擇的顏色的選項(xiàng)。
這些更改的值存儲(chǔ)在與每個(gè)繪圖點(diǎn)關(guān)聯(lián)的Paint對(duì)象中,以便每個(gè)點(diǎn)可以具有自己的特征。

Slider(
value: (selectedMode == SelectedMode.StrokeWidth)
? strokeWidth
: opacity,
max: (selectedMode == SelectedMode.StrokeWidth)
? 50.0
: 1.0,
min: 0.0,
onChanged: (val) {
setState(() {
if (selectedMode == SelectedMode.StrokeWidth)
strokeWidth = val;
else
opacity = val;
});
}),

對(duì)于顏色選擇器,我們使用fuyumi的flutter_colorpicker庫(kù)https://pub.dartlang.org/packages/flutter_colorpicker
這個(gè)項(xiàng)目的代碼可以在github上找到:
https://github.com/sharansingh00002/draw
翻譯自:https://medium.com/flutter-community/drawing-in-flutter-using-custompainter-307a9f1c21f8