Flutter自定义控件分为三大类:
- 组合控件,通过组合其他widget成为一个新的widget。
- 自绘控件,通过使用canvas与paint来完全绘制。
- 继承widget,使用RenderObject来绘制,但最终还是使用canvas来绘制。
本文重点
着重介绍自绘控件,因为所有的widget归根结底都是使用canvas和paint来绘制的,理解了二者,对于其他的widget原理有溯源的功效。
- Canvas:画布
- Paint:画笔
怎么做? - 继承CustomPainter
- 重写paint方法与shouldRepaint方法
- paint提供来canvas和size,canvas用于绘制,size用于确定大小
- shouldRepaint用于确认是否每次都重新绘制
画矩形canvas.drawRect();
void drawRect(Rect rect, Paint paint)
rect 矩形的描述
- Rect.fromCenter({ Offset center, double width, double height }),根据中心点和宽高,定义一个矩形。
- Rect.fromCircle({ Offset center, double radius }),根据中心点和半径定义一个矩形
- Rect.fromLTRB(this.left, this.top, this.right, this.bottom),left左边框距离左边的距离,top上边框距离上边的距离,right右边框距离左边的距离,bottom下边框距离上边的距离。根据这四个值定义一个矩形。
- Rect.fromLTWH(double left, double top, double width, double height),根据左上角顶点和宽高定义一个矩形。
-
Rect.fromPoints(Offset a, Offset b),根据左上角顶点和右下角顶点定义一个矩形。
示例:
image.png
class _MyHomePageState extends State<MyHomePage> {
bool flag = true;
void change(bool value) {
setState(() {
flag = value;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: CustomPaint(
size: Size(380, 560),
painter: MyPainter(),
),
),
);
}
}
class MyPainter extends CustomPainter{
@override
void paint(Canvas canvas, Size size) {
test01(canvas, size);
}
void test00(Canvas canvas, Size size) {
var paint = new Paint()
..color = Colors.orange[200]
..style = PaintingStyle.fill
..isAntiAlias = true;
// 画矩形
canvas.drawRect(Offset.zero & size, paint);
paint
..color = Colors.green;
canvas.drawRect(Rect.fromCenter(width: 200,height: 200,center: Offset(150, 150)), paint);
paint
..color = Colors.blue;
canvas.drawRect(Rect.fromCircle(radius: 50,center: Offset(150, 150)), paint);
paint
..color = Colors.redAccent;
canvas.drawRect(Rect.fromLTRB(10,10,200,100), paint);
paint
..color = Colors.pink;
canvas.drawRect(Rect.fromLTWH(10,250,100,100), paint);
paint
..color = Colors.grey;
canvas.drawRect(Rect.fromPoints(Offset(250, 250),Offset(350, 300)), paint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
// TODO: implement shouldRepaint
return true;
}
}
画圆角矩形canvas.drawRRect
image.pngvoid test01(Canvas canvas, Size size) {
var paint = new Paint()
..color = Colors.orange[200]
..style = PaintingStyle.fill
..isAntiAlias = true;
// 画矩形
Rect rect = Rect.fromCircle(
center: Offset(200, 200), radius: 150);
RRect rRect = RRect.fromRectAndRadius(rect, Radius.circular(30));
canvas.drawRRect(rRect, paint);
}
画环形圆角矩形canvas.drawDRRect
image.pngvoid test011(Canvas canvas, Size size) {
var paint = new Paint()
..color = Colors.orange[200]
..style = PaintingStyle.fill
..isAntiAlias = true;
// 画矩形
Rect rect1 = Rect.fromCircle(
center: Offset(200, 200), radius: 140);
Rect rect2 = Rect.fromCircle(
center: Offset(200, 200), radius: 160);
RRect rRect1 = RRect.fromRectAndRadius(rect1, Radius.circular(20));
RRect rRect2 = RRect.fromRectAndRadius(rect2, Radius.circular(20));
canvas.drawDRRect(rRect2, rRect1, paint);
}
画圆canvas.drawCircle
drawCircle(Offset c, double radius, Paint paint)
- c 中心点
- radius 圆半径
- paint 画笔
示例:
image.png
void test02(Canvas canvas, Size size) {
var paint = new Paint()
..color = Colors.orange[200]
..style = PaintingStyle.fill
..isAntiAlias = true;
// 画矩形
canvas.drawRect(Offset.zero & size, paint);
paint ..color = Colors.blue[200];
canvas.drawCircle(Offset(200, 200), 100, paint);
}
画椭圆canvas.drawOval
image.pngvoid test022(Canvas canvas, Size size) {
var paint = new Paint()
..color = Colors.orange[200]
..style = PaintingStyle.fill
..isAntiAlias = true;
// 画矩形
canvas.drawRect(Offset.zero & size, paint);
paint..color = Colors.blue[200];
canvas.drawOval(
Rect.fromCenter(width: 200, height: 300, center: Offset(150, 250)),
paint);
}
画线canvas.drawLine
void drawLine(Offset p1, Offset p2, Paint paint)
- p1 线的起点
- p2 线的终点
注意:
- 画笔的style 更改为PaintingStyle.stroke
- 可以调整线的粗细 strokeWidth = 3
示例:
image.png
void test03(Canvas canvas, Size size) {
var paint = new Paint()
..color = Colors.orange[200]
..style = PaintingStyle.fill
..isAntiAlias = true;
// 画矩形
canvas.drawRect(Offset.zero & size, paint);
paint
..color = Colors.black
..strokeWidth = 3
..style = PaintingStyle.stroke;
canvas.drawLine(Offset(100, 150), Offset(250, 150), paint);
}
画颜色canvas.drawColor
void drawColor(Color color, BlendMode blendMode)
-
blendMode 是颜色的混合模式
image.png
void test04(Canvas canvas, Size size) {
var paint = new Paint()
..color = Colors.orange[200]
..style = PaintingStyle.fill
..isAntiAlias = true;
// 画矩形
canvas.drawColor(Colors.blue[200], BlendMode.srcIn);
canvas.drawRect(Offset.zero & size/2, paint);
}
画点drawPoints
image.png参数PointModel:
- ui.PointMode.points,// 单独的点
- ui.PointMode.polygon,// 所有的点按给定顺序连成线
- ui.PointMode.lines,//画一条线,起始点为给定数组的前两个点
void test06(Canvas canvas, Size size) {
var paint = new Paint()
..color = Colors.orange[200]
..style = PaintingStyle.fill
..isAntiAlias = true;
// 画矩形
canvas.drawRect(Offset.zero & size, paint);
paint
..style = PaintingStyle.stroke
..strokeWidth = 15
..strokeCap = StrokeCap.round
..color = Colors.black;
canvas.drawPoints(
// ui.PointMode.points,// 单独的点
// ui.PointMode.polygon,// 所有的点按给定顺序连成线
ui.PointMode.lines,//画一条线,起始点为给定数组的前两个点
[Offset(100, 100), Offset(300, 100), Offset(200, 300)], paint);
}
画路径canvas.drawPath
paint ..color = PaintingStyle.fill;
image.png
void test07(Canvas canvas, Size size) {
var paint = new Paint()
..color = Colors.orange[200]
..style = PaintingStyle.fill
..isAntiAlias = true;
// 画矩形
Path path = Path();
path.moveTo(100, 100);
path.lineTo(100, 200);
path.lineTo(200, 100);
path.lineTo(200, 200);
canvas.drawPath(path, paint);
}
paint ..color = PaintingStyle.stroke;
image.png
void test07(Canvas canvas, Size size) {
var paint = new Paint()
..color = Colors.orange[200]
// ..style = PaintingStyle.fill
..style = PaintingStyle.stroke
..strokeWidth = 5
..isAntiAlias = true;
// 画矩形
Path path = Path();
path.moveTo(100, 100);
path.lineTo(100, 200);
path.lineTo(200, 100);
path.lineTo(200, 200);
canvas.drawPath(path, paint);
}
path.close()
image.png
void test07(Canvas canvas, Size size) {
var paint = new Paint()
..color = Colors.orange[200]
// ..style = PaintingStyle.fill
..style = PaintingStyle.stroke
..strokeWidth = 5
..isAntiAlias = true;
// 画矩形
Path path = Path();
path.moveTo(100, 100);
path.lineTo(100, 200);
path.lineTo(200, 100);
path.lineTo(200, 200);
path.close();
canvas.drawPath(path, paint);
}
画弧型
void drawArc(Rect rect, double startAngle, double sweepAngle, bool useCenter, Paint paint)
- rect 弧所属椭圆的外接矩形,用于定位该弧的位置
- startAngle,起始角度,按弧度制,顺时针
- sweepAngle,画多少弧度,一个圆的弧度是 2PI,也就是2*3.14
-
useCenter,是否将弧与中心连接,形成一个扇形
image.png
void test08(Canvas canvas, Size size) {
var paint = new Paint()
..color = Colors.orange[200]
// ..style = PaintingStyle.fill
..style = PaintingStyle.stroke
..strokeWidth = 5
..isAntiAlias = true;
Rect rect = Rect.fromCircle(
center: Offset(200, 200), radius: 100);
canvas.drawArc(rect, 0, 3.14, false, paint);
}
画阴影drawShadow
void drawShadow(Path path, Color color, double elevation, bool transparentOccluder)
- path 阴影区域
- color 阴影颜色
- elevation 阴影高度,一般是向右下
-
transparentOccluder 如果阻塞对象不是不透明的,则阻塞“transparentoccluder”参数应为true.百度翻译的,没明白啥意思
image.png
void test09(Canvas canvas, Size size) {
var paint = new Paint()
..color = Colors.orange[200]
..style = PaintingStyle.fill
..strokeWidth = 5
..isAntiAlias = true;
Path path = Path();
path.moveTo(100, 100);
path.lineTo(100, 200);
path.lineTo(200, 100);
path.lineTo(200, 200);
canvas.drawPath(path, paint);
canvas.drawShadow(path, Colors.orange, 10, true);
}
网友评论