CustomPaint 介紹
CustomPaint class提供了讓用戶自定義widget的能力,它暴露了一個canvas,可以通過這個canvas來繪制widget,CustomPaint會先調(diào)用painter繪制背景,然后再繪制child,最后調(diào)用foregroundPainter來繪制前景,CustomPaint的定義如下
CustomPaint({Key key,
CustomPainter painter,
CustomPainter foregroundPainter,
Size size: Size.zero,
bool isComplex: false,
bool willChange: false,
Widget child })
-
painter:負責(zé)繪制背景的painter -
foregroundPainter: 負責(zé)繪制前景的painter -
size: 控件大小 -
isComplex: 是否復(fù)雜繪制,需要用cache來提高繪制效率 -
willChange: 和isComplex配合使用,當(dāng)啟用緩存時,該屬性代表在下一幀中繪制是否會改變 -
child: 子widget
CustomPainter 介紹
CustomPaint的繪制過程都將會交給CustomPainter來完成,CustomPainter是個抽象接口,在子類化CustomPainter的時候必須要重寫它的paint 跟 shouldRepaint接口,可以根據(jù)自己的場景來選擇性的重寫hitTest跟shouldRebuildSemantics方法。
-
paint: 每當(dāng)CustomPaint需要重繪的時候都會調(diào)用此接口 -
shouldRepaint: 當(dāng)CustomPaint被重新設(shè)置了一個新的painter后會回調(diào)此方法,CustomPaint會根據(jù)shouldRepaint的返回值來判斷是否需要重新繪制ui,譬如新的painter跟舊的painter繪制的內(nèi)容不一樣時,此時shouldRepaint需要返回true來通知CustomPaint重新繪制。
Canvas 介紹
canvas--畫布,真正的繪制是由canvas跟paint來完成的,畫布提供了各種繪制的接口來繪制圖形,除此以外畫布還提供了平移、縮放、旋轉(zhuǎn)等矩陣變換接口,畫布都有固定大小跟形狀,還可以使用畫布提供的裁剪接口來裁剪畫布的大小形狀等等。
常用的繪制接口有更多請查看官方文檔
//畫圓
drawCircle(Offset c, double radius, Paint paint) → void
//畫圖片
drawImage(Image image, Offset p, Paint paint) → void
//畫九宮圖
drawImageNine(Image image, Rect center, Rect dst, Paint paint) → void
//畫線
drawLine(Offset p1, Offset p2, Paint paint) → void
//畫橢圓
drawOval(Rect rect, Paint paint) → void
//畫文字
drawParagraph(Paragraph paragraph, Offset offset) → void
//畫Rect區(qū)域
drawRect(Rect rect, Paint paint) → void
//畫陰影
drawShadow(Path path, Color color, double elevation, bool transparentOccluder) → void
Paint 介紹
Paint---筆畫,是用來設(shè)置在畫布上面繪制圖形時的一些筆畫屬性,如:顏色、線寬、繪制模式、抗鋸齒等等。常用屬性有更多請查看官方文檔
color : 設(shè)置畫筆顏色
isAntiAlias : 設(shè)置畫筆是否扛鋸齒
shader : 著色器,填充形狀或者畫線時用到,如果沒設(shè)置將會使用color
strokeWidth : 設(shè)置畫筆畫線寬度
style :繪制模式,畫線或充滿
CustomPaint 使用
下面這個例子來自于官方,通過CustomPaint 畫出了一個藍天跟太陽出來
class HomeState extends State<HomeWidget> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('CustomPaintDemo'),),
body: Container(
alignment: Alignment.center,
child: CustomPaint(
painter: Sky(),
child: Center(
child: Text(
'Once upon a time...',
style: const TextStyle(
fontSize: 40.0,
fontWeight: FontWeight.w900,
color: Color(0xFFFFFFFF),
),
),
),
)
),
);
}
}
class Sky extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
var rect = Offset.zero & size;
var gradient = RadialGradient(
center: const Alignment(0.7, -0.6),
radius: 0.2,
colors: [const Color(0xFFFFFF00), const Color(0xFF0099FF)],
stops: [0.4, 1.0],
);
canvas.drawRect(
rect,
Paint()..shader = gradient.createShader(rect),
);
}
@override
SemanticsBuilderCallback get semanticsBuilder {
return (Size size) {
// Annotate a rectangle containing the picture of the sun
// with the label "Sun". When text to speech feature is enabled on the
// device, a user will be able to locate the sun on this picture by
// touch.
var rect = Offset.zero & size;
var width = size.shortestSide * 0.4;
rect = const Alignment(0.8, -0.9).inscribe(Size(width, width), rect);
return [
CustomPainterSemantics(
rect: rect,
properties: SemanticsProperties(
label: 'Sun',
textDirection: TextDirection.ltr,
),
),
];
};
}
// Since this Sky painter has no fields, it always paints
// the same thing and semantics information is the same.
// Therefore we return false here. If we had fields (set
// from the constructor) then we would return true if any
// of them differed from the same fields on the oldDelegate.
@override
bool shouldRepaint(Sky oldDelegate) => false;
@override
bool shouldRebuildSemantics(Sky oldDelegate) => false;
}
效果如下:
