<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
上一篇我們介紹了使用 Flutter 的 Canvas 繪製基本圖形的範例,簡單的範例沒什麼好玩的,今天這一篇我們來點有趣的,我們會完成如下圖形的繪製:
通過這一篇,我們可以知道自定義形狀繪製的基本原理,然後可以在這個基礎上繪製你自己想要繪製的圖形。
首先我們來繪製等邊三角形,其實上一篇我們也有繪製等邊三角形,只是那是將三個頂點手動計算出來的,這一篇我們封裝一個繪製等邊三角形的通用方法。老規矩,先定義方法的輸入引數,如下所示:
canvas
:Canvas
畫布color
:繪製顏色startVertex
:三角形的第一個頂點位置,這裡我們其他邊都是相對這個點旋轉的length
:邊長startAngle
:第一條邊相對水平方向旋轉的夾角,這樣我們可以改變夾角來更改三角形的繪製位置。clockwise
:順時針繪製,如果是順時針,則繪製的偏移夾角往順時針方向開始,否則逆時針。filled
:是否填充圖形。void drawEquilateralTriangle( Canvas canvas, { required Color color, required Offset startVertex, required double length, double startAngle = 0, clockwise = true, filled = true, })
等邊三角形基於一個頂點,一條邊和起始角度後就可以計算其他兩個頂點的位置,具體推到通過三角函數就可以了。
具體計算三角形的三個頂點的方法如下,這裡逆時針方向和順時針方向的計算方式有點不同,需要區分一下。
static List<Offset> getEquilateralTriangleVertexes( Offset startVertex, double length, {double startAngle = 0, bool clockwise = true}) { double point2X, point2Y, point3X, point3Y; point2X = startVertex.dx + length * cos(startAngle); point2Y = startVertex.dy - length * sin(startAngle); if (clockwise) { point3X = startVertex.dx + length * cos(pi / 3 + startAngle); point3Y = startVertex.dy - length * sin(pi / 3 + startAngle); } else { point3X = startVertex.dx + length * cos(pi / 3 - startAngle); point3Y = startVertex.dy + length * sin(pi / 3 - startAngle); } return [startVertex, Offset(point2X, point2Y), Offset(point3X, point3Y)]; }
有了頂點我們就可以使用 Path 將頂點連起來就完成等邊三角形的繪製了,繪製三角形的實現方法如下:
void drawEquilateralTriangle( Canvas canvas, { required Color color, required Offset startVertex, required double length, double startAngle = 0, clockwise = true, filled = true, }) { assert(length > 0); Path trianglePath = Path(); List<Offset> vertexes = ShapesUtil.getEquilateralTriangleVertexes( startVertex, length, clockwise: clockwise, startAngle: startAngle, ); trianglePath.moveTo(vertexes[0].dx, vertexes[0].dy); for (int i = 1; i < vertexes.length; i++) { trianglePath.lineTo(vertexes[i].dx, vertexes[i].dy); } trianglePath.close(); Paint paint = Paint(); paint.color = color; if (!filled) { paint.style = PaintingStyle.stroke; } canvas.drawPath(trianglePath, paint); } }
單獨一個三角形沒啥意思,我們通過畫6個等邊三角形,每個三角形旋轉60度,空心繪製看看怎麼樣?
一個 完美的六邊形出來了,再試試12個怎麼樣。
形狀越多,會越接近圓形,你會充分發現對稱之美。下面是我們用24個三角形,填充不同顏色後的效果。有點像一把彩虹傘的傘面了,感覺是不是很美?
上面圖形的實現程式碼如下,其中顏色是通過一個顏色陣列完成的。
int number = 24; for (int i = 0; i < number; ++i) { drawEquilateralTriangle( canvas, color: colors[i], startVertex: Offset(center.width, center.height), length: 120, startAngle: i * 2 * pi / number, clockwise: true, filled: true, ); }
有了上面的彩虹傘一樣的啟發,我們決定來繪製彩虹。彩虹其實比較簡單,繪製7條不同顏色的弧線即可。這裡講一下弧線的繪製約束。如下圖所示,實際上弧線是通過矩形的內接橢圓限制的(這裡用正方形,內接為圓形範例)。外面的矩形限制了橢圓位置和尺寸,而通過 startAngle
(起始角度)和 sweepAngle
(弧線覆蓋的角度範圍)就能夠確定弧線的起點和終點,從而得到一段弧線。注意的是,數學裡我們是逆時針角度為正,但是在 Flutter 預設是順時針為正,因此如果你要從逆時針方向開始角度就要設定為負數。
下面是弧線繪製的範例程式碼:
Path path1 = Path(); Rect rect1 = Rect.fromLTWH(startPoint.dx + (width - innerWidth) / 2, startPoint.dy + (width - innerWidth) / 2, innerWidth, innerWidth); path1.arcTo(rect1, -pi / 6, -2 * pi / 3, true); paint.color = colors[i]; canvas.drawPath(path1, paint);
有了這個基礎,我們通過迴圈 ,繪製7條弧線,保證每條弧線挨著就行。而弧線的線條粗細可以用畫筆的寬度來搞定,程式碼如下。我們這裡每條弧線的中心、起始角度和覆蓋角度是一樣的,通過改變不同弧線的正方形邊長實現彩虹弧線的位置不同,然後畫筆粗細保持為每條彩虹的高度的一半就可以保證每條彩虹是挨著的了。
void drawRainbow( Canvas canvas, { required Offset startPoint, required double width, }) { assert(width > 0); var paint = Paint(); double rowHeight = 12; paint.strokeWidth = rowHeight / 2; List<Color> colors = [ Color(0xFFE05100), Color(0xFFF0A060), Color(0xFFE0E000), Color(0xFF10F020), Color(0xFF2080F5), Color(0xFF104FF0), Color(0xFFA040E5), ]; paint.style = PaintingStyle.stroke; for (var i = 0; i < 7; i++) { double innerWidth = width - i * rowHeight; Path path1 = Path(); Rect rect1 = Rect.fromLTWH(startPoint.dx + (width - innerWidth) / 2, startPoint.dy + (width - innerWidth) / 2, innerWidth, innerWidth); path1.arcTo(rect1, -pi / 6, -2 * pi / 3, true); paint.color = colors[i]; canvas.drawPath(path1, paint); } }
最終效果如下圖所示。
五角星相對來說會複雜一些,主要是要知道通過中心點確定10個頂點的座標,這裡就需要利用二維座標的旋轉公式了,具體可以查閱相關資料,結論是一個點(x2, y2)圍繞另一個點(x1, y1)旋轉某個角度(α)後得到的新座標(x, y)計算方式如下:
x=x1+(x2-x1)*cos(α)-(y2-y1)*sin(α)
y=y1+(y2-y1)*cos(α)+(x2-x1)*sin(α)
有了這個基礎,我們就可以基於五角星的中心點,第一個頂點,邊長(間隔一個點連線的線段長度)來通過旋轉計算其他頂點了。其中外面5頂點一組計算,內部5個頂點一組計算。最終獲取5個頂點的程式碼如下:
static List<Offset> getStarVertexes(Offset center, double length) { assert(length > 0); // 外接圓半徑計算(五角星銳角為36度) double radius = length / 2 / cos(18 / 180 * pi); // 內部頂點的半徑 double innerRadius = radius / (cos(36 / 180 * pi) + sin(36 / 180 * pi) / sin(18 / 180 * pi)); List<Offset> vertexes = []; Offset outerStartVertex = Offset(center.dx, center.dy - radius); Offset innerStartVertex = Offset( center.dx - innerRadius * sin(36 / 180 * pi), center.dy - innerRadius * cos(36 / 180 * pi), ); vertexes.add(outerStartVertex); vertexes.add(innerStartVertex); // 計算方式為以第一個頂點圍繞五角星中心點座標旋轉得到 const double rotateAngle = 72 / 180 * pi; for (int i = 1; i < 5; ++i) { vertexes.add(Offset( center.dx + (outerStartVertex.dx - center.dx) * cos(-i * rotateAngle) - (outerStartVertex.dy - center.dy) * sin(-i * rotateAngle), center.dy + (outerStartVertex.dy - center.dy) * cos(-i * rotateAngle) + (outerStartVertex.dx - center.dx) * sin(-i * rotateAngle), )); vertexes.add(Offset( center.dx + (innerStartVertex.dx - center.dx) * cos(-i * rotateAngle) - (innerStartVertex.dy - center.dy) * sin(-i * rotateAngle), center.dy + (innerStartVertex.dy - center.dy) * cos(-i * rotateAngle) + (innerStartVertex.dx - center.dx) * sin(-i * rotateAngle), )); } return vertexes; }
有了頂點,繪製方式就和三角形一樣了,將頂點連起來就好了。下面是我們繪製了一個常見的五星評分的圖形。
本篇介紹了基於 Flutter 的 CustomPaint
繪製客製化化圖形的範例,可以看到,其實只要 UI 小姐姐給出的圖形能夠用數學表示式表示出來,都可以用 CustomPaint
的 Canvas
來實現。
到此這篇關於詳解利用Flutter中的Canvas繪製有趣的圖形的文章就介紹到這了,更多相關Flutter Canvas圖形內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45