Flutter實現支付寶集五福手畫福字功能

需求

包含需求的具體有:

界面隨著用戶手指的滑動顯示走過軌跡,也就是對應的筆畫。

點擊清空按鈕可以清除所有的筆畫。

點擊撤銷按鈕可以清除上一步畫過的筆畫。

保存所寫的文字樣式到相冊。

實現思路

顯示筆畫軌跡

使用Listener組件對用戶手指落下、滑動和收起的動作進行監聽,在onPointerDown,onPointerMove,onPointerUp3個監聽方法中返回的PointerMoveEvent對象包含瞭手指所在的位置坐標偏移量localPosition,用戶每次滑動時都會記錄下軌跡經過的坐標點,這些坐標點連接起來就是一條線。其次,再配合使用CustomPainter進行畫佈自繪,將所有劃過的點的連接成線使用畫筆繪制在界面上即可。

搜集坐標點:

Listener(
  child: Container(
    alignment: Alignment.center,
    color: Colors.transparent,
    width: double.infinity,
    height: MediaQuery.of(context).size.height,
  ),
  onPointerDown: (PointerDownEvent event) {
    setState(() {
      
    });
  },
  onPointerMove: (PointerMoveEvent event) {
    setState(() {
      
    });
  },
  onPointerUp: (PointerUpEvent event) {
    setState(() {
      
    });
  },
),

繪制:

@override
void paint(Canvas canvas, Size size) {
  myPaint.strokeCap = StrokeCap.round;
  myPaint.strokeWidth = 15.0;
  if (lines.isEmpty) {
    canvas.drawPoints(PointMode.polygon, [Offset.zero, Offset.zero], myPaint);
  } else {
    for (int k = 0; k < lines.length; k++) {
      for (int i = 0; i < lines[k].length - 1; i++) {
        if (lines[k][i] != Offset.zero && lines[k][i + 1] != Offset.zero) {
          canvas.drawLine(lines[k][i], lines[k][i + 1], myPaint);
        }
      }
    }
  }
}

撤銷與清空

看到上面的代碼有的人可能會比較疑惑,繪制時為什麼這麼復雜,還出現瞭雙重循環。這就和撤銷功能有關瞭,先假設不需要撤銷功能,其實我們就可以直接把所有筆畫的點連接到一起進行繪制就可以瞭,但是一旦引入瞭撤銷功能,就要記錄每一筆筆畫,福字筆畫是13畫,那麼理論上是需要記錄13個筆畫的,才能保證每次撤銷時都能正常退回上一次畫過的筆跡,所以第一反應就是使用集合將每一次筆畫記錄下來。而上面也說瞭每一個筆畫其實也是多個坐標點的集合,所以所有筆畫就是一個坐標點集合的集合,即:

/// 所有筆畫劃線集合
List<List<Offset>> _lines = [];

另外,也不難想到,我們可以輕易通過手指按下和手指手指的方法回調來區分筆畫開始和結束。在兩個方法中進行筆畫的add和更新。

onPointerDown: (PointerDownEvent event) {
  setState(() {
    _event = event;
    _points.add(_event?.localPosition ?? Offset.zero);
    _lines.add(_points);
  });
},
onPointerMove: (PointerMoveEvent event) {
  setState(() {
    _event = event;
    _points.add(_event?.localPosition ?? Offset.zero);
    _lines.last = _points;
  });
},
onPointerUp: (PointerUpEvent event) {
  setState(() {
    _event = event;
    _points.add(Offset.zero);
    _lines.last = _points;
  });
  _points = [];
},

而前面說的雙重遍歷這時也比較好理解瞭:

  • 第一層循環是遍歷所有的筆畫,遍歷次數就是福字的筆畫數。
  • 第二層循環是每一個筆畫包括的好多個坐標點,遍歷出來使用drawLine方法繪制到界面上形成一條線。

這樣在進行撤銷操作時,調用list的removeLast方法移除最後一項再刷新界面就能實現退回一筆的效果瞭,清空就是清空筆畫集合。

保存到相冊

保存相冊主要是引入瞭兩個插件庫:permission_handlerimage_gallery_saver,一個用來獲取存儲權限,一個用來保存到相冊。 使用RepaintBoundary組件將畫佈包裹起來,並指定key,在點擊保存時按順序調用如下方法先獲取截圖後保存即可:

RenderRepaintBoundary boundary =
    key.currentContext!.findRenderObject() as RenderRepaintBoundary;
var image = await boundary.toImage(pixelRatio: 3.0);
ByteData? byteData = await image.toByteData(format: ImageByteFormat.png);
_postBytes = byteData?.buffer.asUint8List();
var result = await ImageGallerySaver.saveImage(_postBytes!);

完整代碼與demo下載

github地址

安卓手機掃碼下載

到此這篇關於Flutter實現支付寶集五福手畫福字功能的文章就介紹到這瞭,更多相關Flutter畫福字內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: