Flutter 的繪制主要涉及兩個Widget: CustomPainter, CustomPaint
CustomPainter:提供畫布的組件狠裹; 有幾個主要的參數:
a. painter : 繪制的對象绍些,是一個CustomPaint皆看。它的繪制是在children之前才避。如果設置了children货裹,該painter繪制的內容會被覆蓋迎吵。
b. foregroundPainter: 繪制的對象躲撰,是一個CustomPaint。它的繪制是在children之后击费。該painter繪制的內容會覆蓋children 拢蛋。
c. size: 繪制區(qū)域的大小,如果有child就忽略此屬性直接用child的size蔫巩。
d. child :
CustomPaint:是一個抽象類谆棱,要實現繪制的邏輯必須繼承該抽象類,并實現它的paint和shouldRepaint方法圆仔。
void paint(Canvas canvas, Size size);: 里邊實現具體的繪制邏輯垃瞧。
-- canvas: 畫布
-- size: 畫布的大小
bool shouldRepaint(covariant CustomPainter oldDelegate); : 控制是否重繪
繪制
Paint 畫筆
介紹幾個常用的參數:
(1) color: 畫筆的顏色
(2)strokeWidth: 線的寬度
(3)style: 填充模式,有兩種: PaintingStyle.fill : 填充坪郭; PaintingStyle.stroke: 空心
(4)strokeCap:
(5)blendMode: 重疊部分的處理个从,一般在截取Image后合并Image用。
a. src: 只顯示源圖
b. dst: 只顯示目標圖
c. srcOver: 都顯示歪沃,重疊部分是src覆蓋在dst的上邊嗦锐;
d. dstOver: 都顯示,重疊部分是dst覆蓋在src的上邊沪曙;
e. srcIn; // 只顯示重疊部分的src圖奕污,透明部分也是不顯示的。
f. dstIn; // 只顯示重疊部分的dst圖液走,透明部分也是不顯示的菊值。
... 還有好多不說了外驱,用的時候自己看注釋。
p = Paint()
..color = Colors.orange // 畫筆的顏色
..strokeWidth = 2.0 // 線的寬度
..style = PaintingStyle.stroke // fill: 填充腻窒, stroke: 空心
..strokeCap = StrokeCap.butt // 轉折處的處理
..blendMode = BlendMode.dstIn; // 重疊處的處理模式昵宇,clear,src, dst, srcIn,dstIn等等。
繪制線段
// 第一個參數表示起點坐標
// 第二個參數表示終點坐標
// 第三個參數是畫筆
canvas.drawLine(Offset(10, 10), Offset(100, 100), p);
繪制矩形
繪制矩形需要用到Rect儿子, 而React的創(chuàng)建可以通過Offset和Size來完成瓦哎,Offset 決定他左上角的坐標 Size 決定他的大小。Rect rect = offset & size;
// 矩形的長寬
Size size = Size(200, 300);
// 矩形左上角的坐標
Offset offset = Offset(200, 200);
// 合成Rect柔逼,為什么可以這樣合成蒋譬? 官方給的!看下邊--->
Rect rect = offset & size;
canvas.drawRect(
rect,
Paint()
..color = Colors.red
..strokeWidth = 3.0);
/// A Rect can be created with one its constructors or from an [Offset] and a
/// [Size] using the `&` operator:
///
/// ```dart
/// Rect myRect = const Offset(1.0, 2.0) & const Size(3.0, 4.0);
/// ```
繪制多邊形
繪制多變形要用到Path的moveTo和lineTo放發(fā)愉适,
void moveTo(double x, double y): 將畫筆的起點移動到(x,y)坐標犯助。
void lineTo(double x, double y): 從當前點繪制一條直線到(x,y)坐標。
canvas.drawPath(
Path()
..moveTo(30, 200)
..lineTo(200, 200)
..lineTo(100, 300)
..lineTo(50, 330)
..lineTo(30, 300)
..close(),
Paint()
..color = Colors.lightBlue
..strokeWidth = 1.0);
繪制圓
// 第一個參數是原點坐標
// 第二個參數是半徑
// 第三個參數是畫筆
canvas.drawCircle(Offset(100, 100), 50, p);
繪制陰影
// Path 的用法在上邊繪制多變形的時候已經說過了 moveTo, lineTo .
canvas.drawShadow(
Path()
..moveTo(30.0, 30.0)
..lineTo(320.0, 30.0)
..lineTo(120.0, 160.0)
..lineTo(30.0, 160.0)
..close(),
// 陰影的顏色
Colors.blue,
// 陰影擴散的范圍
3,
false);
繪制文本
ParagraphBuilder pb = ParagraphBuilder(ParagraphStyle(
textAlign: TextAlign.left, // 對齊方式
fontWeight: FontWeight.w600, // 粗體
fontStyle: FontStyle.normal, // 正常 or 斜體
fontSize: 18,
))
..pushStyle(dartUi.TextStyle(color: Colors.black26))
..addText('''
// 測試文本的繪制
// 繪制陰影
canvas.drawShadow(
Path()
..moveTo(30.0, 30.0)
..lineTo(320.0, 30.0)
..lineTo(120.0, 160.0)
..lineTo(30.0, 160.0)
..close(),
Colors.blue,
3,
false);
''');
// 繪制的寬度
ParagraphConstraints pc =
ParagraphConstraints(width: 350.0);
Paragraph paragraph = pb.build()..layout(pc);
canvas.drawParagraph(paragraph, Offset(30, 300));
繪制Image
繪制的代碼如下维咸,當然他有好幾種繪制方式(drawImage剂买, drawImageRect, drawImageNine)癌蓖。代碼看起來很簡單瞬哼,但是如果你直接這樣寫的話,是會報錯的租副。折騰了我很久坐慰,最后找出的原因是 圖片的加載是耗時的,不要放在這里邊加載用僧,放到外邊加載完成后通過參數傳進 CustomPainter 就不會報錯了结胀。 不信你直接在這里加載image然后在Future的then里去調用下面的代碼,也是不行的T鹧0芽纭!
一般用 canvas.drawImageRect 來繪制而不用canvas.drawImage沼死。 canvas.drawImageRect可以指定寬高着逐,可以截圖∫庵看一下源碼你會發(fā)現drawImage 的內部也是調用drawImageRect 來實現的耸别。
使用如下:
canvas.drawImage(
image, dartUi.Offset(0, image.height.toDouble() + 30), Paint());
canvas.drawImageRect(
image,
// 本次要截取的區(qū)域--相對于原圖(該坐標以原圖的左上角為原點0,0, 截圖一個寬高都為60的區(qū)域)
Rect.fromLTWH(0, 0, 60, 60),
// 要被截取的原圖所在的區(qū)域
Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble()),
Paint());
通過繪制實現圖片的截圖功能
// 裁剪畫布县钥,區(qū)域為(60, 60, 190, 90)
canvas.clipRect(Rect.fromLTWH(60, 60, 190, 90));
類似Android秀姐, 可以通過裁剪畫布的功能做一些特殊的繪制。 一般裁剪之前會調用canvas.store ()來保存當前的畫布若贮,等到在裁剪過的畫布上做完相關的操作之后可以通過 canvas.restore()來恢復之前的畫布省有。
canvas.store(): 保存當前的畫布
canvas.restore ():恢復裁剪之前的畫布(之前保存的)
這倆要成對出現痒留。
可以跑的代碼:
import 'package:flutter/material.dart';
void main() =>
runApp(
StartPage()
);
class StartPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: TestPage(),
);
}
}
class TestPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("flutter 繪制demo"),),
body: CustomPaint(foregroundPainter: PaintDemo(),),
);
}
}
class PaintDemo extends CustomPainter {
Paint _paint;
PaintDemo() {
_paint = Paint()
..color = Colors.orange // 畫筆的顏色
..strokeWidth = 2.0 // 線的寬度
..style = PaintingStyle.fill // fill: 填充, stroke: 空心
;
}
@override
void paint(Canvas canvas, Size size) {
canvas.drawLine(Offset(10, 10), Offset(60, 10), _paint);
canvas.drawCircle(Offset(100, 100), 50, _paint);
Size size = Size(200, 300);
// 可以通過Offset和Size來創(chuàng)建一個Rect蠢沿,Offset 決定他右上角的坐標 Size 決定他的大小
Rect rect = Offset(200, 200) & size;
canvas.drawRect(
rect,
Paint()
..color = Colors.red
..strokeWidth = 3.0);
// 繪制陰影
canvas.drawShadow(
Path()
..moveTo(30.0, 500.0)
..lineTo(320.0, 500.0)..lineTo(120.0, 660.0)..lineTo(30.0, 660.0)
..close(),
Colors.blue,
3,
false);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
到此伸头, 關于Flutter的繪制就介紹的差不多了,歡迎指正舷蟀。
關于圖片的繪制恤磷,代碼稍微多一些,沒放上去野宜,有需要留言扫步。