什麼是CustomPaint?
在Android中,有時候我們需要使用 Canvas 和 Paint 來進行繪製一些複雜的圖形,在 Flutter 中,當然也有可以讓你自由繪製的方案,他就是 CustomPaint。
CustomPaint 也是一個 Widget,你可以把它嵌到檢視樹的任意一個節點位置。
先看看它的常用屬性:
屬性 | 型別 | 說明 |
---|---|---|
painter | CustomPainter | 背景畫筆,繪製內容會顯示在child子節點後面 |
foregroundPainter | CustomPainter | 前景畫筆,繪製內容會顯示在child子節點前面 |
size | Size | 設定繪製區域的大小。如果有child,則忽略該引數,且繪製區域為child的尺寸 |
isComplex | bool | 是否複雜的繪製,如果是,Flutter會應用一些快取策略來減少重複渲染的開銷。預設false |
willChange | bool | 和isComplex配合使用,當啟用快取時,該屬性代表在下一幀中繪製是否會改變。預設false |
child | Widget | 沒錯,CustomPaint是可以包含一個子節點的 |
CustomPaint
是一個繼承自SingleChildRenderObjectWidget
的控制元件,不能用setState的方式來重新整理它。
painter
就是我們的主繪製工具,它是一個CustomPainter
;foregroundPainter
是用來繪製前景的工具;
size
為畫布大小,這個size會傳遞給Painter
;
isComplex
和willChange
是告訴Flutter你的CustomPaint
是否複雜到需要使用cache相關的功能;
child
屬性我們一般不填,即使你是想要在你的CustomPaint
上新增一些其他的佈局,也不建議放在child屬中性,因為你會發現你並不會得到你想要的結果。
CustomPainter 是一個抽象類,你需要繼承它實現自己的邏輯。
class MyPainter extends CustomPainter {
@override
paint(Canvas canvas, Size size) {
// do
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
繼承 CustomPainter 最重要的是實現 paint(Canvas canvas, Size size)
和 shouldRepaint(CustomPainter oldDelegate)
這兩個函式。
paint()
中是繪製邏輯,可以在這獲得畫布 Canvas 和 畫布的大小 Size。shouldRepaint()
返回 true 才會進行重繪,否則就只會繪製一次。你可以通過一些條件判斷來決定是否每次繪製,這樣能夠節約系統資源。
例如:
@override
void paint(Canvas canvas, Size size) {
final outerThickess = max(trackWidth, max(progressWidth, thumbSize));
Size constrainedSize = new Size(
size.width - outerThickess,
size.height - outerThickess
);
// paint track.
final center = new Offset(size.width / 2, size.height /2);
final radius = min(constrainedSize.width, constrainedSize.height) / 2;
canvas.drawCircle(center, radius, trackPaint);
// paint progress.
final progressAngle = 2 * pi * progressPercent;
canvas.drawArc(new Rect.fromCircle(
center: center,
radius: radius
), -pi / 2, progressAngle, false, progressPaint);
// paint thumb.
final thumbAngle = 2 * pi * thumbPosition - (pi / 2);
final thumbX = cos(thumbAngle) * radius;
final thumbY = sin(thumbAngle) * radius;
final thumbCenter = new Offset(thumbX, thumbY) + center;
final thumbRadius = thumbSize / 2;
canvas.drawCircle(thumbCenter, thumbRadius, thumbPaint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
// TODO: implement shouldRepaint
return true;
}
這裡簡單的列一下,一些常用的canvas繪製API:
// 繪製弧線
drawArc(Rect rect, double startAngle, double sweepAngle, bool useCenter, Paint paint)
// 繪製圖片
drawImage(Image image, Offset p, Paint paint)
// 繪製圓
drawCircle(Offset c, double radius, Paint paint)
// 繪製線條
drawLine(Offset p1, Offset p2, Paint paint)
// 繪製橢圓
drawOval(Rect rect, Paint paint)
// 繪製文字
drawParagraph(Paragraph paragraph, Offset offset)
// 繪製路徑
drawPath(Path path, Paint paint)
// 繪製點
drawPoints(PointMode pointMode, List<Offset> points, Paint paint)
// 繪製Rect
drawRect(Rect rect, Paint paint)
// 繪製陰影
drawShadow(Path path, Color color, double elevation, bool transparentOccluder)
1、繪製直線
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..isAntiAlias = true
..color = Colors.pink
..strokeWidth = 10
..style = PaintingStyle.fill;
Paint paint1 = Paint()
..isAntiAlias = true
..color = Colors.blue
..strokeWidth = 10
..style = PaintingStyle.fill;
Paint paint2 = Paint()
..isAntiAlias = true
..color = Colors.green
..strokeWidth = 10
..style = PaintingStyle.fill;
/// Offset(),橫縱座標偏移
canvas.drawLine(Offset(85, 100), Offset(285, 100), paint);
canvas.drawLine(Offset(85, 100), Offset(200, 300), paint1);
canvas.drawLine(Offset(285, 100), Offset(200, 300), paint2);
}
2、繪製弧線
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..isAntiAlias = true
..color = Colors.green
..strokeCap = StrokeCap.round
..strokeWidth = 10
..style = PaintingStyle.stroke;
Paint paint1 = Paint()
..isAntiAlias = true
..color = Colors.blue
..strokeCap = StrokeCap.round
..strokeWidth = 10
..style = PaintingStyle.stroke;
/// Offset(),橫縱座標偏移
/// void drawArc(Rect rect, double startAngle, double sweepAngle, bool useCenter, Paint paint)
/// Rect來確認圓弧的位置, 開始的弧度、結束的弧度、是否使用中心點繪製(圓弧是否向中心閉合)、以及paint.
final center = new Offset(170, 200);
canvas.drawArc(new Rect.fromCircle(
center: center,
radius: size.width / 2
), -pi / 2, 2 * pi * 0.5, false, paint);
canvas.drawArc(new Rect.fromCircle(
center: Offset(170, 300),
radius: size.width / 2
), pi / 2, 2 * pi * 0.5, false, paint1);
}
3、繪製圓
Paint paint = Paint()
..isAntiAlias = true
..color = Colors.green
..strokeCap = StrokeCap.round
..strokeWidth = 10
..style = PaintingStyle.fill;
Paint paint1 = Paint()
..isAntiAlias = true
..color = Colors.blue
..strokeCap = StrokeCap.round
..strokeWidth = 10
..style = PaintingStyle.stroke;
canvas.drawCircle(Offset(150.0, 200.0), 50.0, paint1);
canvas.drawCircle(Offset(150.0, 350.0), 50.0, paint);