flutter自定義View(CustomPainter) 之 canvas的方法總結

前有大佬分享了用CustomPaint畫一個自定義的CircleProgressBar的文章, 今天我分享一波自定義View(CustomPaint)的一些基礎知識git

畫布canvas

畫布是一個矩形區域,咱們能夠控制其每一像素來繪製咱們想要的內容github

canvas 擁有多種繪製點、線、路徑、矩形、圓形、以及添加圖像的方法,結合這些方法咱們能夠繪製出變幻無窮的畫面。canvas

雖然,畫布能夠畫這些東西,可是決定這些圖形顏色、粗細表現的仍是畫筆。markdown

畫筆Paint

Paint很是好理解,就是咱們用來畫圖形的工具,咱們能夠設置畫筆的顏色、粗細、是否抗鋸齒、筆觸形狀以及做畫風格。工具

經過這些屬性咱們能夠很方便的來定製本身的UI效果,固然咱們在「做畫」的過程當中能夠定義多個畫筆,這樣更方便咱們對圖形的繪製oop

畫筆Paint的屬性

canvas中有多個與繪製相關的方法,如drawLine()、drawRect()、drawOval()、drawOval()、等方法。spa

可是,僅僅使用canvas這個畫布還不夠,咱們還須要一個畫筆paint,咱們可使用以下代碼來構建paint3d

Paint _paint = Paint()
    ..color = Colors.blueAccent //畫筆顏色
    ..strokeCap = StrokeCap.round //畫筆筆觸類型
    ..isAntiAlias = true //是否啓動抗鋸齒
    ..blendMode = BlendMode.exclusion //顏色混合模式
    ..style = PaintingStyle.fill //繪畫風格,默認爲填充
    ..colorFilter = ColorFilter.mode(Colors.blueAccent,
        BlendMode.exclusion) //顏色渲染模式,通常是矩陣效果來改變的,可是flutter中只能使用顏色混合模式
    ..maskFilter = MaskFilter.blur(BlurStyle.inner, 3.0) //模糊遮罩效果,flutter中只有這個
    ..filterQuality = FilterQuality.high //顏色渲染模式的質量
    ..strokeWidth = 15.0; //畫筆的寬度
複製代碼

固然,在正常的開發中通常不會使用這麼多的屬性,你們能夠根據須要去具體的瞭解和使用。code

畫布canvas的方法

如下內容基於此畫筆繪製:orm

Paint _paint = new Paint()
    ..color = Colors.blueAccent
    ..strokeCap = StrokeCap.round
    ..isAntiAlias = true
    ..strokeWidth = 5.0
    ..style = PaintingStyle.stroke;
複製代碼

繪製直線

void drawLine(Offset p1, Offset p2, Paint paint)

使用給定的塗料在給定點之間繪製一條線。 該行被描邊,此調用忽略[Paint.style]的值。 p1p2參數爲兩個點的座標 , 在這兩點之間繪製一條直線。

eg : canvas.drawLine(Offset(20.0, 20.0), Offset(100.0, 100.0), _paint)
複製代碼

在這裏插入圖片描述

繪製點drawPoints

void drawPoints(PointMode pointMode, List points, Paint paint)

繪製點也是很是的簡單,3個參數分別爲: PointMode枚舉,座標 list 和 paint PointMode的枚舉類型有三個,points(點),lines(線,隔點鏈接),polygon(線,相鄰鏈接)

canvas.drawPoints(
        ///PointMode的枚舉類型有三個,points(點),lines(線,隔點鏈接),polygon(線,相鄰鏈接)
        PointMode.points,
        [
          Offset(20.0, 130.0),
          Offset(100.0, 210.0),
          Offset(100.0, 310.0),
          Offset(200.0, 310.0),
          Offset(200.0, 210.0),
          Offset(280.0, 130.0),
          Offset(20.0, 130.0),
        ],
        _paint..color = Colors.redAccent);
複製代碼

爲了方便演示,咱們在上面定義了7個點,第一個和最後一個點重合。

而後咱們設置PointMode爲points看下效果。 在這裏插入圖片描述

而後咱們把PointMode改成lines PointMode.lines

PointMode爲lines時,兩個點相互鏈接,也就是說第一個和第二個點鏈接,第三個跟第四個鏈接,若是最後只有一個點就捨棄不鏈接了,在咱們的例子中有7個點,因此圖中只有三條連線。

而後咱們把PointMode改成lines 在這裏插入圖片描述

對,你看的沒有錯跟上面繪製線段的效果是同樣的,相鄰點互相鏈接。

繪製圓rawCircle

void drawCircle(Offset c, double radius, Paint paint)

參數分別爲:圓心的座標、半徑和paint便可。 圓形是否填充或描邊(或二者)由Paint.style控制。

//繪製圓 參數(圓心,半徑,畫筆)
     canvas.drawCircle(
        Offset(100.0, 350.0),
        30.0,
        _paint
          ..color = Colors.greenAccent
          ..style = PaintingStyle.stroke //繪畫風格改成stroke
        );
複製代碼

在這裏插入圖片描述

在這裏我將畫筆Paint的style改爲了stroke 而後咱們將畫筆style改爲fill (填充) ,fill也是畫筆的style的默認值. 在這裏插入圖片描述 填充以後,這個圓就變成實心的了.

繪製橢圓drawOval

void drawOval(Rect rect, Paint paint)

繪製一個軸對稱的橢圓形 參數爲一個矩形和畫筆paint.

//使用左上和右下角座標來肯定矩形的大小和位置,橢圓是在這個矩形之中內切的
    Rect rect1 = Rect.fromPoints(Offset(150.0, 200.0), Offset(300.0, 250.0));
    canvas.drawOval(rect1, _paint);
複製代碼

在這裏插入圖片描述

在前面咱們已經講過了使用Rect即可確認這個矩形的大小和位置。

其實,Rect也有多種構建方式:

fromPoints(Offset a, Offset b)
使用左上和右下角座標來肯定矩形的大小和位置

fromCircle({ Offset center, double radius })
使用圓的圓心點座標和半徑和肯定外切矩形的大小和位置

fromLTRB(double left, double top, double right, double bottom)
使用矩形左邊的X座標、矩形頂部的Y座標、矩形右邊的X座標、矩形底部的Y座標來肯定矩形的大小和位置

fromLTWH(double left, double top, double width, double height)
使用矩形左邊的X座標、矩形頂部的Y座標矩形的寬高來肯定矩形的大小和位置
複製代碼

繪製圓弧drawArc

void drawArc(Rect rect, double startAngle, double sweepAngle, bool useCenter, Paint paint)

首先仍是須要Rect來確認圓弧的位置,還須要開始的弧度、結束的弧度、是否使用中心點繪製(圓弧是否向中心閉合)、以及paint.

弧度

根據定義,一週的弧度數爲2πr/r=2π,360°角=2π弧度,所以,1弧度約爲57.3°,即57°17’44.806’’,1°爲π/180弧度,近似值爲0.01745弧度,周角爲2π弧度,平角(即180°角)爲π弧度,直角爲π/2弧度。

特殊的弧度:
弧度
0
30° π/6
45° π/4
60° π/3
90° π/2
120° 2π/3
180° π
270° 3π/2
360°
//繪製圓弧
    // Rect來確認圓弧的位置,還須要開始的弧度、結束的弧度、是否使用中心點繪製、以及paint弧度
    Rect rect2 = Rect.fromCircle(center: Offset(200.0, 50.0), radius: 80.0);
    canvas.drawArc(rect2, 0.0, 0.8, false, _paint);

複製代碼

在這裏插入圖片描述 繪製個90度的弧度

const PI = 3.1415926;
    Rect rect2 = Rect.fromCircle(center: Offset(200.0, 50.0), radius: 80.0);
    canvas.drawArc(rect2, 0.0, PI / 2, false, _paint);
複製代碼

定義π爲3.1415926,定義開始的角度爲0°掃過的角度爲PI / 2(90°),設置userCenter爲false 在這裏插入圖片描述 將useCenter改爲true 試試: 在這裏插入圖片描述 發現圓弧向中心點閉合了.

繪製圓角矩形drawDRRect

void drawRRect(RRect rrect, Paint paint)

使用RRect肯定矩形大小及弧度,使用paint來完成繪製。

RRect構建起來也很是的方便,直接使用fromRectAndRadius便可

RRect.fromRectAndRadius(rect, radius)

rect依然用來表示矩形的位置和大小,radius用來表示圓角的大小。

//用Rect構建一個邊長50,中心點座標爲100,100的矩形
    Rect rect = Rect.fromCircle(center: Offset(100.0, 150.0), radius: 50.0);
    //根據上面的矩形,構建一個圓角矩形
    RRect rrect = RRect.fromRectAndRadius(rect, Radius.circular(20.0));
    canvas.drawRRect(rrect, _paint);
複製代碼

在這裏插入圖片描述

將圓角的半徑設置爲邊長(從20改爲50)試一下: 在這裏插入圖片描述 就變成了圓.

繪製雙圓角矩形drawRRect

void drawDRRect(RRect outer, RRect inner, Paint paint)

和drawRRect相似,使用RRect肯定內部、外部矩形大小及弧度,使用paint來完成繪製。

//繪製兩個矩形
    Rect rect1 = Rect.fromCircle(center: Offset(100.0, 100.0), radius: 60.0);
    Rect rect2 = Rect.fromCircle(center: Offset(100.0, 100.0), radius: 40.0);

    //分別繪製外部圓角矩形和內部的圓角矩形
    RRect outer = RRect.fromRectAndRadius(rect1, Radius.circular(10.0));
    RRect inner = RRect.fromRectAndRadius(rect2, Radius.circular(10.0));
    canvas.drawDRRect(outer, inner, _paint);
複製代碼

使用Rect.fromCircle來建立Rect,使用RRect.fromRectAndRadius來建立RRect 在這裏插入圖片描述

能夠看到兩個圓角矩形,固然咱們也能夠嘗試調整角度的度數大小。

//繪製兩個矩形
    Rect rect1 = Rect.fromCircle(center: Offset(100.0, 100.0), radius: 60.0);
    Rect rect2 = Rect.fromCircle(center: Offset(100.0, 100.0), radius: 40.0);

    //分別繪製外部圓角矩形和內部的圓角矩形
    RRect outer = RRect.fromRectAndRadius(rect1, Radius.circular(30.0));
    RRect inner = RRect.fromRectAndRadius(rect2, Radius.circular(5.0));
    canvas.drawDRRect(outer, inner, _paint);
複製代碼

在這裏插入圖片描述

你甚至能夠調整角度的大小使兩個矩形都變成圓來造成一個圓環.

繪製路徑drawPath

void drawPath(Path path, Paint paint)

繪製路徑,首先須要一個要繪製的路徑path,而後就是這個paint了。

Path的經常使用方法:

方法名 做用
moveTo 將路徑起始點移動到指定的位置
relativeMoveTo 相對於當前位置移動到
lineTo 從當前位置鏈接指定點
relativeLineTo 相對當前位置鏈接到
arcTo 曲線
conicTo 貝塞爾曲線
add** 添加其餘圖形,如addArc,在路徑是添加圓弧
contains 路徑上是否包括某點
transfor 給路徑作matrix4變換
combine 結合兩個路徑
close 關閉路徑,鏈接路徑的起始點
reset 重置路徑,恢復到默認狀態

eg:

//新建了一個path,而後將路徑起始點移動到座標(100,100)的位置
    Path path = new Path()..moveTo(100.0, 100.0);

    path.lineTo(200.0, 200.0);

    canvas.drawPath(path, _paint);
複製代碼

首先新建了一個path,而後將路徑起始點移動到座標(100,100)的位置, 而後從這個位置鏈接(200,200)的點. 在這裏插入圖片描述

咱們也能夠繪製多個路徑:

Path path = new Path()..moveTo(100.0, 100.0);

    path.lineTo(200.0, 200.0);
    path.lineTo(100.0, 300.0);
    path.lineTo(150.0, 350.0);
    path.lineTo(150.0, 500.0);
    
    canvas.drawPath(path, _paint);
複製代碼

在這裏插入圖片描述

使用二階貝塞爾曲線繪製弧線:

void arcTo(Rect rect, double startAngle, double sweepAngle, bool forceMoveTo)

rect咱們都知道了,是一個矩形,startAngle是開始的弧度,sweepAngle是結束的弧度 重點介紹一下forceMoveTo. forceMoveTo:

  • 若是「forceMoveTo」參數爲false,則添加一條直線段和一條弧段。
  • 若是「forceMoveTo」參數爲true,則啓動一個新的子路徑,其中包含一個弧段。

例如:

Path path = new Path()..moveTo(100.0, 100.0);
    Rect rect = Rect.fromCircle(center: Offset(200.0, 200.0), radius: 60.0);
    path.arcTo(rect, 0.0, 3.14, false);
    canvas.drawPath(path, _paint);
複製代碼

在這裏插入圖片描述 這裏,咱們利用貝塞爾曲線繪製了一個半圓,由於起始點的座標是(100,100),而咱們繪製貝塞爾曲線的時候,曲線的原點是(200,200)半徑,60,因此咱們移動到(200,260)的位置再畫這個曲線.

由於forceMoveTo此時爲false,因此從起始點到曲線的起始點畫出了直線路徑, 改成true能夠看到,由於啓動了一個新的子路徑,因此那條線段沒有了:

在這裏插入圖片描述

固然,你甚至能夠用貝塞爾曲線直接畫一個圓:

Rect rect = Rect.fromCircle(center: Offset(200.0, 200.0), radius: 60.0);

    path.arcTo(rect, 0.0, 3.14*2, false);

    canvas.drawPath(path, _paint);
複製代碼

在這裏插入圖片描述

使用三階貝塞爾曲線繪製❤:

void cubicTo(double x1, double y1, double x2, double y2, double x3, double y3)

var width = 200;
    var height = 300;
    path.moveTo(width / 2, height / 4);
    path.cubicTo((width * 6) / 7, height / 9, (width * 13) / 13,
        (height * 2) / 5, width / 2, (height * 7) / 12);
    canvas.drawPath(path, _paint);

    Path path2 = new Path();
    path2.moveTo(width / 2, height / 4);
    path2.cubicTo(width / 7, height / 9, width / 21, (height * 2) / 5,
        width / 2, (height * 7) / 12);
    canvas.drawPath(path2, _paint);
複製代碼

看一下效果: 在這裏插入圖片描述

而後咱們改變paint的樣式:

canvas.drawPath(path, _paint); 
 替換爲:
 canvas.drawPath(
        path,
        _paint
          ..style = PaintingStyle.fill
          ..color = Colors.red);
複製代碼

咱們將畫筆的顏色改爲紅色,樣式改成填充: )

繪製顏色drawColor

void drawColor(Color color, BlendMode blendMode)

咱們先繪製一個圓:

canvas.drawCircle(Offset(100.0, 100.0), 50.0, _paint);
複製代碼

在這裏插入圖片描述 而後咱們添加一行代碼:

canvas.drawCircle(Offset(100.0, 100.0), 50.0, _paint);
    canvas.drawColor(Colors.red, BlendMode.color);  // 添加這行
複製代碼

在這裏插入圖片描述

能夠看到,圓的顏色變成了紅色, 咱們還能夠改變BlendMode, 例如: BlendMode.colorDodge 在這裏插入圖片描述 更多效果能夠查詢BlendMode源碼.

繪製圖片drawImage

void drawImage(Image image, Offset p, Paint paint)

將給定的[image]以其左上角的[偏移量]繪製到畫布中 首先咱們須要獲取本地圖片文件,而後繪製圖片便可

全文相關代碼已提交到 github

相關文章
相關標籤/搜索