Flutter中自定義組件一般有兩種方式:
- 通過已有widget進(jìn)行組合
- 通過CustomPaint進(jìn)行繪制
下面主要介紹下CustomPaint繪制方式。
1. 認(rèn)識(shí)CustomPaint
CustomPaint繼承自SingleChildRenderObjectWidget,即它可以在通過嵌套引入到widget樹中躲叼,并且可以有一個(gè)child子widget蛙酪。它的構(gòu)造方法如下:
const CustomPaint({
Key key,
this.painter,
this.foregroundPainter,
this.size = Size.zero,
this.isComplex = false,
this.willChange = false,
Widget child,
}) : assert(size != null),
assert(isComplex != null),
assert(willChange != null),
super(key: key, child: child);
painter和foregroundPainter需要接收CustomPainter對(duì)象促脉,是CustomPaint核心助币。CustomPainter是進(jìn)行UI繪制的核心類猴蹂,繪制時(shí), CustomPaint 首先在畫布上調(diào)用 painter繪制 , 然后再繪制它的 child Widget, child 繪制完成后再調(diào)用 foregroundPainter 進(jìn)行繪制蓬网。
size屬性標(biāo)識(shí)繪制區(qū)域大小窒所,但當(dāng)CustomPaint有child,該屬性將會(huì)忽略帆锋,而使用child的大小為繪制區(qū)域大小吵取。
isComplex和willChange用于控制繪制層緩存處理的,這里暫不討論锯厢。
2. CustomPainter
可實(shí)現(xiàn)CustomPainter子類進(jìn)行UI繪制
void paint(Canvas canvas, Size size);
實(shí)現(xiàn)paint方法進(jìn)行真正的繪制皮官,canvas是畫布對(duì)象,size是繪制區(qū)域实辑,是從CustomPaint中size屬性傳遞得到的捺氢。繪制過程與Android原生開發(fā)十分類似,連API都十分相像剪撬,這點(diǎn)對(duì)熟悉Android原生開發(fā)者真是太友好了摄乒。
2.1 Paint
Paint對(duì)象是畫筆對(duì)象,就是繪圖工具残黑,我們可以設(shè)置畫筆的顏色缺狠、粗細(xì)、是否抗鋸齒萍摊、筆觸形狀以及作畫風(fēng)格等,通過這些屬性我們可以很方便的來定制自己的UI效果如叼,在繪制的過程中可以定義多個(gè)畫筆冰木,以便實(shí)現(xiàn)多種風(fēng)格圖形的集合。
Paint _paint = Paint()
..color = Colors.pink //畫筆顏色
..strokeCap = StrokeCap.round //畫筆筆觸類型
..isAntiAlias = true //是否啟動(dòng)抗鋸齒
..blendMode = BlendMode.exclusion //顏色混合模式
..style = PaintingStyle.fill //繪畫風(fēng)格笼恰,默認(rèn)為填充
..colorFilter = ColorFilter.mode(Colors.blueAccent,
BlendMode.exclusion) //顏色渲染模式踊沸,一般是矩陣效果來改變的,但是flutter中只能使用顏色混合模式
..maskFilter = MaskFilter.blur(BlurStyle.inner, 3.0) //模糊遮罩效果,flutter中只有這個(gè)
..filterQuality = FilterQuality.high //顏色渲染模式的質(zhì)量
..strokeWidth = 15.0; //畫筆的寬度
根據(jù)需求選擇合適的畫筆屬性社证,完成你的繪制逼龟。
2.2 Canvas
Canvas是繪制的畫布,它包含了很多繪制方法追葡,可以繪制出各種形狀的圖形腺律。需要注意的是奕短,畫布是應(yīng)用所有控件都在使用的, 所以通過這個(gè)畫布其實(shí)是可以繪制充滿屏幕的內(nèi)容的,每次繪制都應(yīng)該限制在本控件的區(qū)域(Size)內(nèi), 以免繪制覆蓋到其他組件匀钧。
下面介紹下Canvas的繪制方法:
2.2.1 繪制點(diǎn)
void drawPoints(PointMode pointMode, List<Offset> points, Paint paint)
PointMode是個(gè)枚舉
enum PointMode {
/// Draw each point separately.僅繪制單獨(dú)的點(diǎn)
points,
/// Draw each sequence of two points as a line segment.繪制連線翎碑,兩兩連線
lines,
/// Draw the entire sequence of point as one line.繪制封閉連線,上個(gè)點(diǎn)連接下個(gè)點(diǎn)
polygon,
}
Offset是相對(duì)于繪制區(qū)域的偏移坐標(biāo)之斯,可以定義點(diǎn)坐標(biāo)
2.2.2 繪制線
void drawLine(Offset p1, Offset p2, Paint paint)
p1日杈、p2為線段兩個(gè)端點(diǎn)
2.2.3 繪制矩形
void drawRect(Rect rect, Paint paint)
Rect定義矩形的大小位置,有多種構(gòu)造方式:
//使用左上和右下角坐標(biāo)來確定矩形的大小和位置
fromPoints(Offset a, Offset b)
//使用圓的圓心點(diǎn)坐標(biāo)和半徑和確定外切矩形的大小和位置
fromCircle({ Offset center, double radius })
//使用矩形左邊的X坐標(biāo)佑刷、矩形頂部的Y坐標(biāo)莉擒、矩形右邊的X坐標(biāo)、矩形底部的Y坐標(biāo)來確定矩形的大小和位置
fromLTRB(double left, double top, double right, double bottom)
//使用矩形左邊的X坐標(biāo)瘫絮、矩形頂部的Y坐標(biāo)矩形的寬高來確定矩形的大小和位置
fromLTWH(double left, double top, double width, double height)
2.2.4 繪制圓角矩形
void drawRRect(RRect rrect, Paint paint)
RRect描述圓角矩形涨冀,他通過Rect和Radius來構(gòu)造
RRect.fromRectAndRadius(rect, radius)
//舉例說明
Rect rect = Rect.fromCircle(center: Offset(100.0, 200.0), radius: 30.0);
RRect rrect = RRect.fromRectAndRadius(rect, Radius.circular(20.0));
2.2.5 繪制圓
void drawCircle(Offset c, double radius, Paint paint)
畫圓比較簡單,c表示圓心位置檀何,radius是半徑蝇裤。
2.2.6 繪制橢圓
void drawOval(Rect rect, Paint paint)
橢圓使用外接矩形確定大小位置,rect就是外接矩形频鉴。
2.2.7 繪制弧形
void drawArc(Rect rect, double startAngle, double sweepAngle, bool useCenter, Paint paint)
繪制弧形栓辜,先確定弧形對(duì)應(yīng)的橢圓,同樣地用外接矩形rect確定橢圓垛孔,然后根據(jù)起始點(diǎn)和結(jié)束點(diǎn)角度來確定那一段弧度藕甩,startAngle,sweepAngle分別代表起始和結(jié)束點(diǎn)角度周荐,角度用弧度表示法狭莱。
useCenter表示是否連接閉合形狀,userCenter = false表示不閉合概作,即畫一段弧線腋妙,userCenter = true表示閉合,即繪制一個(gè)扇形讯榕。
2.2.8 繪制路徑
void drawPath(Path path, Paint paint)
繪制路徑骤素,關(guān)鍵在于構(gòu)建路徑Path,可以直接new Path對(duì)象愚屁,然后通過path方法可以連接出圖形厦酬,path關(guān)鍵方法如下:
moveTo //移動(dòng)到路徑起始位置
lineTo //用直線連接指定點(diǎn)
arcTo //用曲線連接到指定點(diǎn)
conicTo //用二階貝塞爾曲線連接到指定點(diǎn)
cubicTo //用三階貝塞爾曲線連接到指定點(diǎn)
contains //判斷當(dāng)前路徑上是否包含某點(diǎn)
close //路徑閉合签舞,用直線連接到起始點(diǎn)
reset //重置路徑,恢復(fù)到默認(rèn)狀態(tài)
還有其他方法,有興趣可以查看API醋闭。