Flutter 繪製 Tiled Lines

前言

前幾天發現了一個使用 <canvas> 繪製圖形的教程 generative artistry 感受頗有意思,嘗試用 Flutter 實現。本文實現第一篇教程的圖形 Tiled Lines 效果以下。web

建立畫布

首先使用一個 Container 控件建立一個 320*320 大小的繪製區域,添加 CustomPaint 畫布和一個繼承 CustomPainter 的畫筆 TiledLinesPainter。關於 CustomPaintCustomPainter 的知識能夠查閱這篇文章 使用 Flutter 繪製圖表(一)柱狀圖📊canvas

import 'package:flutter/material.dart';
 class TiledLines extends StatelessWidget {  @override  Widget build(BuildContext context) {  return Scaffold(  body: Center(  child: Container(  width: 320.0,  height: 320.0,  decoration: BoxDecoration(  border: Border.all(  color: Colors.black,  width: 1.0,  ),  ),  child: CustomPaint(  painter: TiledLinesPainter(),  ),  ),  ),  );  } }  class TiledLinesPainter extends CustomPainter {  @override  void paint(Canvas canvas, Size size) {}   bool shouldRepaint(TiledLinesPainter oldDelegate) => false; }  複製代碼

繪製線條

建立好畫布後在 TiledLinesPainterpaint 方法裏進行繪製。添加一個 _drawLine 方法用來繪製線條,繪製線條須要起始點和終止點,經過參數將數值傳入。less

class TiledLinesPainter extends CustomPainter {
 void _drawLine(  Canvas canvas,  double x,  double y,  double width,  double height,  ) {  final Paint paint = Paint()  ..strokeCap = StrokeCap.square  ..strokeWidth = 2;   Offset p1 = Offset(x, y);  Offset p2 = Offset(x + width, y + height);   canvas.drawLine(p1, p2, paint);  }   @override  void paint(Canvas canvas, Size size) {  _drawLine(canvas, 0, 0, size.width, size.height);  }   bool shouldRepaint(TiledLinesPainter oldDelegate) => false; } 複製代碼

加入隨機性

使用 Random().nextBool() 方法建立一個隨機的布爾值,在繪製線條以前改變起始點和終止點的座標,這樣 _drawLine 方法就有了繪製不一樣方向的線條的能力。dom

void _drawLine(
 Canvas canvas,  double x,  double y,  double width,  double height,  ) {  final bool isLeftToRight = Random().nextBool();   final Paint paint = Paint()  ..strokeCap = StrokeCap.square  ..strokeWidth = 2;   Offset p1;  Offset p2;   if (isLeftToRight) {  p1 = Offset(x, y);  p2 = Offset(x + width, y + height);  } else {  p1 = Offset(x + width, y);  p2 = Offset(x, y + height);  }   canvas.drawLine(p1, p2, paint); } 複製代碼

繪製更多的線條

能夠繪製更多的線條嘍!給 TiledLinesPainter 添加一個 step 屬性,表示在畫布上每隔多長距離繪製一條線。使用 step 將畫布分割爲多個小的方格,在每一個小的方格里面繪製線條。編輯器

class TiledLinesPainter extends CustomPainter {
 final double step;   TiledLinesPainter(this.step);   void _drawLine(  Canvas canvas,  double x,  double y,  double width,  double height,  ) {  final bool isLeftToRight = Random().nextBool();   final Paint paint = Paint()  ..strokeCap = StrokeCap.square  ..strokeWidth = 2;   Offset p1;  Offset p2;   if (isLeftToRight) {  p1 = Offset(x, y);  p2 = Offset(x + width, y + height);  } else {  p1 = Offset(x + width, y);  p2 = Offset(x, y + height);  }   canvas.drawLine(p1, p2, paint);  }   @override  void paint(Canvas canvas, Size size) {  for (double x = 0; x < size.width; x += step) {  for (double y = 0; y < size.height; y += step) {  _drawLine(canvas, x, y, step, step);  }  }  }   bool shouldRepaint(TiledLinesPainter oldDelegate) => false; }  //...  TiledLinesPainter(20) 複製代碼

繪製邊框和陰影

最後給畫布添加邊框和陰影效果,大功告成!👏 感謝閱讀。ide

import 'dart:math';
import 'package:flutter/material.dart';  class TiledLines extends StatelessWidget {  @override  Widget build(BuildContext context) {  List<BoxShadow> shadows = [];  double opacity = 0.1;   // 添加畫布陰影  for (double i = 1; i <= 16; i++) {  opacity -= 0.01;  opacity = opacity > 0.01 ? opacity : 0.01;   shadows.add(  BoxShadow(  offset: Offset(-i, i),  color: Color.fromRGBO(0, 0, 0, opacity),  blurRadius: 2,  spreadRadius: 1,  ),  );  }   return Scaffold(  body: Center(  child: Container(  width: 320.0,  height: 320.0,  decoration: BoxDecoration(  // 添加畫布邊框  border: Border.all(  color: Colors.black,  width: 20.0,  ),  boxShadow: shadows,  ),  child: Container(  color: Colors.white,  padding: const EdgeInsets.all(20.0),  child: CustomPaint(  painter: TiledLinesPainter(20),  ),  ),  ),  ),  );  } }  class TiledLinesPainter extends CustomPainter {  final double step;   TiledLinesPainter(this.step);   void _drawLine(  Canvas canvas,  double x,  double y,  double width,  double height,  ) {  // 建立隨機性  final bool isLeftToRight = Random().nextBool();   final Paint paint = Paint()  ..strokeCap = StrokeCap.square  ..strokeWidth = 2;   Offset p1;  Offset p2;   // 設置線條的起始點和終止點  if (isLeftToRight) {  p1 = Offset(x, y);  p2 = Offset(x + width, y + height);  } else {  p1 = Offset(x + width, y);  p2 = Offset(x, y + height);  }   canvas.drawLine(p1, p2, paint);  }   @override  void paint(Canvas canvas, Size size) {  // 使用 step 分割畫布,建立小的繪製方格  for (double x = 0; x < size.width; x += step) {  for (double y = 0; y < size.height; y += step) {  _drawLine(canvas, x, y, step, step);  }  }  }   bool shouldRepaint(TiledLinesPainter oldDelegate) => false; }  複製代碼

參考

Tiled Linespost

本文使用 mdnice 排版ui

相關文章
相關標籤/搜索