Flutter CustomPaint 使用介绍
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter CustomPaint 使用介绍相关的知识,希望对你有一定的参考价值。
参考技术A CustomPaint class提供了让用户自定义widget的能力,它暴露了一个canvas,可以通过这个canvas来绘制widget,CustomPaint会先调用painter绘制背景,然后再绘制child,最后调用foregroundPainter来绘制前景,CustomPaint的定义如下CustomPaint的绘制过程都将会交给CustomPainter来完成,CustomPainter是个抽象接口,在子类化CustomPainter的时候必须要重写它的 paint 跟 shouldRepaint 接口,可以根据自己的场景来选择性的重写 hitTest 跟 shouldRebuildSemantics 方法。
canvas--画布,真正的绘制是由canvas跟paint来完成的,画布提供了各种绘制的接口来绘制图形,除此以外画布还提供了平移、缩放、旋转等矩阵变换接口,画布都有固定大小跟形状,还可以使用画布提供的裁剪接口来裁剪画布的大小形状等等。
常用的绘制接口有 更多请查看官方文档
Paint---笔画,是用来设置在画布上面绘制图形时的一些笔画属性,如:颜色、线宽、绘制模式、抗锯齿等等。常用属性有 更多请查看官方文档
color : 设置画笔颜色
isAntiAlias : 设置画笔是否扛锯齿
shader : 着色器,填充形状或者画线时用到,如果没设置将会使用color
strokeWidth : 设置画笔画线宽度
style :绘制模式,画线或充满
下面这个例子来自于官方,通过 CustomPaint 画出了一个蓝天跟太阳出来
效果如下:
如何在 Flutter 中绘制自定义形状卡片
【中文标题】如何在 Flutter 中绘制自定义形状卡片【英文标题】:How to draw a custom shape card in flutter 【发布时间】:2020-12-24 08:07:37 【问题描述】:我只想制作这样的卡片
【问题讨论】:
使用 CustomPaint : api.flutter.dev/flutter/widgets/CustomPaint-class.html 你需要一个自定义的ShapeBorder
类 - 像 BeveledRectangleBorder
/ CircleBorder
/ ContinuousRectangleBorder
/ RoundedRectangle
/ BorderStadiumBorder
这样的类间接扩展该类(你也可以扩展 OutlinedBorder
如果你愿意)
@pskink 你能寄一份样品吗?
paste.ubuntu.com/p/C5QCzsF7gg
【参考方案1】:
代码如下,我使用CustomPaint
Widget 来绘制自定义形状,然后在Card
Widget 内部使用stack 来正确放置小部件。
我没有把图片改成粉红色来显示图片:
这是 Card Widget 的代码,然后是 CustomPainter
类:
Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50.0)),
elevation: 10.0,
child: Container(
width: 300.0,
height: 400.0,
child: Stack(
alignment: Alignment.bottomCenter,
children: [
// This will hold the Image in the back ground:
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50.0),
color: Colors.pink[100]),
),
// This is the Custom Shape Container
Positioned(
bottom: 0.0,
left: 0.0,
child: Container(
color: Colors.red,
child: CustomPaint(
painter: CustomContainerShapeBorder(
height: 100.0,
width: 300.0,
radius: 50.0,
),
),
),
),
// This Holds the Widgets Inside the the custom Container;
Positioned(
bottom: 10.0,
child: Container(
height: 80.0,
width: 260.0,
color: Colors.grey.withOpacity(0.6),
child: null,
),
),
],
),
),
),
自定义画家类:
/// The CustomContainerShapeBorder should be reactibe with different sizes,
/// If it isn't then chamge the offset values.
class CustomContainerShapeBorder extends CustomPainter
final double height;
final double width;
final Color fillColor;
final double radius;
CustomContainerShapeBorder(
this.height: 400.0,
this.width: 300.0,
this.fillColor: Colors.white,
this.radius: 50.0,
);
@override
void paint(Canvas canvas, Size size)
Path path = new Path();
path.moveTo(0.0, -radius);
path.lineTo(0.0, -(height - radius));
path.conicTo(0.0, -height, radius, -height, 1);
path.lineTo(width - radius, -height);
path.conicTo(width, -height, width, -(height + radius), 1);
path.lineTo(width, -(height - radius));
path.lineTo(width, -radius);
path.conicTo(width, 0.0, width - radius, 0.0, 1);
path.lineTo(radius, 0.0);
path.conicTo(0.0, 0.0, 0.0, -radius, 1);
path.close();
canvas.drawPath(path, Paint()..color = fillColor);
@override
bool shouldRepaint(CustomPainter oldDelegate)
return true;
输出: 灰色的容器是用来描绘Custom Shape里面的内容
整个代码:
import 'package:flutter/material.dart';
void main()
runApp(MyApp());
class MyApp extends StatelessWidget
// This widget is the root of your application.
@override
Widget build(BuildContext context)
return MaterialApp(
title: 'Custom Card Design',
theme: ThemeData(
primarySwatch: Colors.amber,
),
home: MyHomePage(),
);
class MyHomePage extends StatefulWidget
@override
_MyHomePageState createState() => _MyHomePageState();
class _MyHomePageState extends State<MyHomePage>
@override
Widget build(BuildContext context)
return Container(
color: Colors.amber,
child: Center(
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50.0)),
elevation: 10.0,
child: Container(
width: 300.0,
height: 400.0,
child: Stack(
alignment: Alignment.bottomCenter,
children: [
// This will hold the Image in the back ground:
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50.0),
color: Colors.pink[100]),
),
// This is the Custom Shape Container
Positioned(
bottom: 0.0,
left: 0.0,
child: Container(
color: Colors.red,
child: CustomPaint(
painter: CustomContainerShapeBorder(
height: 100.0,
width: 300.0,
radius: 50.0,
),
),
),
),
// This Holds the Widgets Inside the the custom Container;
Positioned(
bottom: 10.0,
child: Container(
height: 80.0,
width: 260.0,
color: Colors.grey.withOpacity(0.6),
child: null,
),
),
],
),
),
),
));
/// The CustomContainerShapeBorder should be reactibe with different sizes,
/// If it isn't then chamge the offset values.
class CustomContainerShapeBorder extends CustomPainter
final double height;
final double width;
final Color fillColor;
final double radius;
CustomContainerShapeBorder(
this.height: 400.0,
this.width: 300.0,
this.fillColor: Colors.white,
this.radius: 50.0,
);
@override
void paint(Canvas canvas, Size size)
Path path = new Path();
path.moveTo(0.0, -radius);
path.lineTo(0.0, -(height - radius));
path.conicTo(0.0, -height, radius, -height, 1);
path.lineTo(width - radius, -height);
path.conicTo(width, -height, width, -(height + radius), 1);
path.lineTo(width, -(height - radius));
path.lineTo(width, -radius);
path.conicTo(width, 0.0, width - radius, 0.0, 1);
path.lineTo(radius, 0.0);
path.conicTo(0.0, 0.0, 0.0, -radius, 1);
path.close();
canvas.drawPath(path, Paint()..color = fillColor);
@override
bool shouldRepaint(CustomPainter oldDelegate)
return true;
【讨论】:
谢谢,但我使用自定义 ShapeBorder 。这是更好的选择 在形状边框类内使用相同的Path设计【参考方案2】:The output screen我希望这会有所帮助。 代码:
import 'package:flutter/material.dart';
main()
runApp(MyApp());
class MyApp extends StatelessWidget
@override
Widget build(BuildContext context)
return MaterialApp(
title: 'Drawing Paths',
home: Container(
color: Colors.white,
child: CustomPaint(
painter: CurvePainter(),
),
),
);
class CurvePainter extends CustomPainter
@override
void paint(Canvas canvas, Size size)
var paint = Paint();
paint.color = Colors.blueAccent;
paint.style = PaintingStyle.fill;
var path = Path();
path.moveTo(size.width, size.height * 0.7);
path.quadraticBezierTo(size.width * 0.99, size.height * 0.79,
size.width * 0.8, size.height * 0.8);
path.lineTo(size.width * 0.08, size.height * 0.8);
path.quadraticBezierTo(size.width * 0.001, size.height * 0.81,
0, size.height * 0.86);
path.lineTo(0, size.height * 0.95);
path.quadraticBezierTo(size.width * 0.001 , size.height * 0.98,
size.width * 0.08, size.height * 0.99);
path.lineTo(size.width * 0.8, size.height * 0.99);
path.quadraticBezierTo(size.width * 0.99, size.height * 0.99,
size.width, size.height * 0.89);
canvas.drawPath(path, paint);
@override
bool shouldRepaint(CustomPainter oldDelegate)
return true;
【讨论】:
【参考方案3】:对于任何类型的自定义设计,您都可以使用此工具创建https://shapemaker.web.app/#/
【讨论】:
以上是关于Flutter CustomPaint 使用介绍的主要内容,如果未能解决你的问题,请参考以下文章
用Flutter做桌上弹球?聊聊绘图(Canvas&CustomPaint)API
用Flutter做桌上弹球?聊聊绘图(Canvas&CustomPaint)API