Flutter 繪制Paint

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的繪制就介紹的差不多了,歡迎指正舷蟀。
關于圖片的繪制恤磷,代碼稍微多一些,沒放上去野宜,有需要留言扫步。

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市匈子,隨后出現的幾起案子河胎,更是在濱河造成了極大的恐慌,老刑警劉巖虎敦,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件游岳,死亡現場離奇詭異,居然都是意外死亡原茅,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進店門堕仔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來擂橘,“玉大人,你說我怎么就攤上這事摩骨⊥ㄕ辏” “怎么了?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵恼五,是天一觀的道長昌罩。 經常有香客問我,道長灾馒,這世上最難降的妖魔是什么茎用? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮睬罗,結果婚禮上轨功,老公的妹妹穿的比我還像新娘。我一直安慰自己容达,他們只是感情好古涧,可當我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著花盐,像睡著了一般羡滑。 火紅的嫁衣襯著肌膚如雪菇爪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天柒昏,我揣著相機與錄音凳宙,去河邊找鬼。 笑死昙楚,一個胖子當著我的面吹牛近速,可吹牛的內容都是我干的。 我是一名探鬼主播堪旧,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼削葱,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了淳梦?” 一聲冷哼從身側響起析砸,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎爆袍,沒想到半個月后首繁,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡陨囊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年弦疮,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蜘醋。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡胁塞,死狀恐怖,靈堂內的尸體忽然破棺而出压语,到底是詐尸還是另有隱情啸罢,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布胎食,位于F島的核電站扰才,受9級特大地震影響,放射性物質發(fā)生泄漏厕怜。R本人自食惡果不足惜衩匣,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望粥航。 院中可真熱鬧舵揭,春花似錦、人聲如沸躁锡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽映之。三九已至拦焚,卻和暖如春蜡坊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背赎败。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工秕衙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人僵刮。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓据忘,卻偏偏與公主長得像,于是被迫代替她去往敵國和親搞糕。 傳聞我的和親對象是個殘疾皇子勇吊,可洞房花燭夜當晚...
    茶點故事閱讀 45,515評論 2 359

推薦閱讀更多精彩內容