Flutter 爲咱們提供了許多標準的組件可供咱們在項目中使用,可是咱們也經常須要本身去自定義 View,而自定義 View 最多見也是最基礎的就是使用 Path 了。html
接下來正式開始學習 Path。git
先來看一段代碼。github
import 'package:flutter/material.dart';
void main() => runApp(
MaterialApp(
home: PathExample(),
),
);
class PathExample extends StatelessWidget {
@override
Widget build(BuildContext context) {
return CustomPaint(
painter: PathPainter(),
);
}
}
class PathPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = Colors.red
..style = PaintingStyle.stroke
..strokeWidth = 8.0;
Path path = Path();
// TODO: do operations here
path.close();
canvas.drawPath(path, paint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
複製代碼
在上面代碼裏,咱們主頁面是 StatelessWidget 類型的組件,在 build 方法裏面返回的是 CustomPaint 這個 Widget,而 CustomPaint 須要使用的 painter 是咱們自定義的 PathPainter 。CustomPaint 這個組件爲咱們提供了一個畫布 (canvas),咱們可使用咱們自定義的 CustomPainter 在這個畫布上把 paint() 這個方法裏面指定的內容繪製上去。編程
對於繪製有關的選項,咱們能夠經過 Paint 組件來進行設置,包括顏色、樣式、畫筆粗細等。canvas
Paint paint = Paint()
..color = Colors.blueAccent //畫筆顏色
..strokeCap = StrokeCap.round //畫筆筆觸類型
..isAntiAlias = true //是否啓動抗鋸齒
..blendMode = BlendMode.exclusion //顏色混合模式
..style = PaintingStyle.fill //繪畫風格,默認爲填充
..colorFilter = ColorFilter.mode(Colors.blueAccent,
BlendMode.exclusion) //顏色渲染模式
..maskFilter = MaskFilter.blur(BlurStyle.inner, 3.0) //模糊遮罩效果
..filterQuality = FilterQuality.high //顏色渲染模式的質量
..strokeWidth = 5.0; //畫筆的寬度
複製代碼
接下來咱們就能夠定義一個 Path 對象來決定畫什麼了。 Path 這個對象實際上是一些列須要繪製的元素的集合,這些元素在繪製的時候都是根據一個起始點來繪製的(默認的 Path 的起始點是 (0,0) )。api
最後須要使用 canvas 的 drawPath 方法來繪製 path ,這個方法須要兩個參數一個是 path 另外一個是 paint 。bash
使用 Path 進行繪圖的基本流程差很少就是這些。對於手機上的座標系統,以下所示,左上角爲座標原點。微信
moveTo 方法就把繪製的七點移動到指定的位置。less
@override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = Colors.red
..style = PaintingStyle.stroke
..strokeWidth = 8.0;
Path path = Path();
// 將起點移動到屏幕中心
path.moveTo(size.width / 2, size.height / 2);
canvas.drawPath(path, paint);
}
複製代碼
lineTo 方法就是從起點繪製一條直線到 lineTo 裏面指定的一個點。ide
@override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = Colors.red
..style = PaintingStyle.stroke
..strokeWidth = 8.0;
Path path = Path();
// 從左上角起點到右下角終點
path.lineTo(size.width, size.height);
canvas.drawPath(path, paint);
}
複製代碼
quadraticBezierTo 是繪製二階貝塞爾曲線的。
從上圖能夠看到,繪製貝塞爾曲線須要三個點,一個起點,一個控制點,一個終點。
@override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = Colors.red
..style = PaintingStyle.stroke
..strokeWidth = 8.0;
Path path = Path();
path.moveTo(0, size.height / 2);
path.quadraticBezierTo(size.width / 2, size.height, size.width, size.height / 2);
canvas.drawPath(path, paint);
}
複製代碼
cubicTo 是繪製三階貝塞爾曲線的。
三階貝塞爾須要兩個控制點。
@override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = Colors.red
..style = PaintingStyle.stroke
..strokeWidth = 8.0;
Path path = Path();
path.cubicTo(size.width / 4, 3 * size.height / 4, 3 * size.width / 4, size.height / 4, size.width, size.height);
canvas.drawPath(path, paint);
}
複製代碼
conicTo 方法也是繪製二次曲線的,和 quadraticBeizerTo 方法相似,可是這個方法主要是受到 weight 參數的控制。 當 weight 大於 1 時,繪製的是雙曲線,等於 1 時,繪製的是拋物線,小於1 時,繪製的是橢圓。
@override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = Colors.red
..style = PaintingStyle.stroke
..strokeWidth = 8.0;
Path path = Path();
path.conicTo(size.width / 4, 3 * size.height / 4, size.width, size.height, 20);
canvas.drawPath(path, paint);
}
複製代碼
arcTo 方法是繪製弧線的,方法原型以下:
void arcTo(Rect rect, double startAngle, double sweepAngle, bool forceMoveTo)
複製代碼
須要四個參數:
@override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = Colors.red
..style = PaintingStyle.stroke
..strokeWidth = 8.0;
// Method to convert degree to radians
num degToRad(num deg) => deg * (Math.pi / 180.0);
Path path = Path();
path.arcTo(Rect.fromLTWH(size.width / 2, size.height / 2, size.width / 4, size.height / 4), degToRad(0), degToRad(90), true);
canvas.drawPath(path, paint);
}
複製代碼
繪製矩形。
@override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = Colors.red
..style = PaintingStyle.stroke
..strokeWidth = 8.0;
Path path = Path();
// Adds a rectangle
path.addRect(Rect.fromLTWH(size.width / 2, size.height / 2, size.width / 4, size.height / 4));
canvas.drawPath(path, paint);
}
複製代碼
繪製橢圓。
@override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = Colors.red
..style = PaintingStyle.stroke
..strokeWidth = 8.0;
Path path = Path();
// Adds an oval
path.addOval(Rect.fromLTWH(size.width / 2, size.height / 2, size.width / 4, size.height / 4));
canvas.drawPath(path, paint);
}
複製代碼
繪製弧線相似與 arcTo
@override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = Colors.red
..style = PaintingStyle.stroke
..strokeWidth = 8.0;
// Method to convert degree to radians
num degToRad(num deg) => deg * (Math.pi / 180.0);
Path path = Path();
// Adds a quarter arc
path.addArc(Rect.fromLTWH(0, 0, size.width, size.height), degToRad(180), degToRad(90));
canvas.drawPath(path, paint);
}
複製代碼
繪製多邊形。能夠指定多邊形的頂點,而且最後一個參數是 ture 時,最後一個點和第一個點會鏈接,多邊形閉合, false 時,不會閉合。
@override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = Colors.red
..style = PaintingStyle.stroke
..strokeWidth = 8.0;
Path path = Path();
// Adds a polygon from the starting point to quarter point of the screen and lastly
// it will be in the bottom middle. Close method will draw a line between start and end.
path.addPolygon([
Offset.zero,
Offset(size.width / 4, size.height / 4),
Offset(size.width / 2, size.height)
], false);
canvas.drawPath(path, paint);
}
複製代碼
繪製圓角矩形,圓角弧度由最後一個參數控制。
@override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = Colors.red
..style = PaintingStyle.stroke
..strokeWidth = 8.0;
Path path = Path();
path.addRRect(
RRect.fromRectAndRadius(Rect.fromLTWH(size.width / 2, size.height / 2, size.width / 4, size.height / 4), Radius.circular(16))
);
canvas.drawPath(path, paint);
}
複製代碼
class CircleProgressBarPainter extends CustomPainter {
//背景
Paint _paintBackground;
//前景
Paint _paintForeground;
var currentValue;
CircleProgressBarPainter(this.currentValue) {
_paintBackground = Paint()
..color = Colors.blue
..strokeCap = StrokeCap.round
..style = PaintingStyle.stroke
..strokeWidth = 10.0
..isAntiAlias = true;
_paintForeground = Paint()
..color = Colors.red
..strokeCap = StrokeCap.round
..style = PaintingStyle.stroke
..strokeWidth = 10.0
..isAntiAlias = true;
}
@override
void paint(Canvas canvas, Size size) {
//畫背景
canvas.drawCircle(Offset(size.width / 2, size.height / 2), size.width / 2,
_paintBackground);
Rect rect = Rect.fromCircle(
center: Offset(size.width / 2, size.height / 2),
radius: size.width / 2,
);
//畫弧形進度
canvas.drawArc(rect, 0.0, currentValue * Math.pi / 180, false, _paintForeground);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return false;
}
}
複製代碼
使用
return Container(
width: width,
height: height,
padding: EdgeInsets.all(20),
child: CustomPaint(
child: Center(
child: Text(
(progressAnimation.value / 3.6).round().toString(),
style: TextStyle(fontSize: 24,color: Colors.blue),
),
),
painter: CircleProgressBarPainter(progressAnimation.value)
),
);
複製代碼
效果: