概述
1、绘制图片系列
因为读取图片是一个异步的操作,在读取完毕之后,需要重新渲染界面,也就是可变状态。现在要有一个概念:
画布只承担绘制工作,一切数据的来源由使用者来提供
。也就是将ui.Image对象作为参数传递給PaperPainter,画板质询要关注于操作。
class Paper extends StatefulWidget {
@override
_PaperState createState() => _PaperState();
}
class _PaperState extends State<Paper> {
ui.Image? _image;
@override
void initState() {
super.initState();
_loadImage();
}
void _loadImage() async {
_image =
await loadImageFromAssets('assets/images/wy_300x200.jpg');
setState(() {});
}
@override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
child: CustomPaint(painter: PaperPainter(_image)));
}
// 方法在上面已给出,不再重复书写...
//读取 assets 中的图片
Future<ui.Image>? loadImageFromAssets(String path) async {
ByteData data = await rootBundle.load(path);
return decodeImageFromList(data.buffer.asUint8List());
}
}
好,这样我们就将一个画板创造出来了。并且上面会有一张我们drawImage出来的图片。
好的,这样的话我们的图片就成功的在画布上渲染出来了。然后我们再来思考一个问题,我们有没有可能将这个图片给他按照矩形裁剪出来呢?
void _drawImageRect(Canvas canvas) {
if (image != null) {
canvas.drawImageRect(
image!,
Rect.fromCenter(
center: Offset(image!.width/2, image!.height/2), width: 60, height: 60),
Rect.fromLTRB(0, 0, 100, 100).translate(200, 0),
_paint);
canvas.drawImageRect(
image!,
Rect.fromCenter(
center: Offset(image!.width/2, image!.height/2-60), width: 60, height: 60),
Rect.fromLTRB(0, 0, 100, 100).translate(-280, -100),
_paint);
canvas.drawImageRect(
image!,
Rect.fromCenter(
center: Offset(image!.width/2+60, image!.height/2), width: 60, height: 60),
Rect.fromLTRB(0, 0, 100, 100).translate(-280, 50),
_paint);
}
}
这样,我们就可以将我们的图片做各种不同的裁剪绘制了。
4、图片域绘制
drawImageNine
中主要是两个矩形区域,center和dst。center表示从资源图片image上一块可缩放的矩形域,所以原点是图片的左上角。dst表示将扣出的图片填充到画布的哪个矩形域当中去。所以圆点是画布原点。这样很容易画出气泡的效果。即指定区域进行缩放,其余不动。
void _drawImageNine(Canvas canvas) {
if (image != null) {
canvas.drawImageNine(
image!,
Rect.fromCenter(center: Offset(image!.width/2, image!.height-6.0),
width: image!.width-20.0, height: 2.0),
Rect.fromCenter(center: Offset(0, 0,), width:300, height: 120),
_paint);
canvas.drawImageNine(
image!,
Rect.fromCenter(center: Offset(image!.width/2, image!.height-6.0),
width: image!.width-20.0, height: 2.0),
Rect.fromCenter(center: Offset(0, 0,), width:100, height: 50).translate(250, 0),
_paint);
canvas.drawImageNine(
image!,
Rect.fromCenter(center: Offset(image!.width/2, image!.height-6.0),
width: image!.width-20.0, height: 2.0),
Rect.fromCenter(center: Offset(0, 0,), width:80, height: 250).translate(-250, 0),
_paint);
}
}
5、绘制图集drawAtlas
这个方法有7个参数,用起来比较复杂,主要作用是,在画布上绘制一张图片的很多部分,比如雪碧图(Sprite)将需要的图片放在一张图里面。另外通过
drawAtlas
绘制的效率更加的高
- 定义每个Sprite类封装图片元素数据
class Sprite{
// 矩形区域
Rect position;
// 距离中心点偏移
Offset? offset;
// 透明度
int? alpha;
// 旋转角度
double rotation;
Sprite({this.offset, this.alpha, this.rotation = 0, required this.position});
}
- 绘制一张图片
绘制时必须要传入的参数是,
图片 ui.Image
、变换列表List<RSTransform>
、矩形列表List<Rect>
,下面通过矩形域就可以绘制这张图片:
void _drawSprite(Canvas canvas){
// 添加一个 Sprite
allSprites.add(Sprite(
position: Rect.fromLTWH(0, 325, 257, 166),
offset: Offset(0, 0),
alpha: 255,
rotation: 0));
// 通过 allSprites 创建 RSTransform 集合
final List<RSTransform> transforms = allSprites
.map((sprite) => RSTransform.fromComponents(
rotation: sprite.rotation,
scale: 1.0,
anchorX: 0,
anchorY: 0,
translateX: sprite.offset!.dx,
translateY: sprite.offset!.dy,
))
.toList();
// 通过 allSprites 创建 Rect 集合
final List<Rect> rects =
allSprites.map((sprite) => sprite.position).toList();
canvas.drawAtlas(image!, transforms, rects, null, null, null, _paint);
}
- 图形的变换
我们在定义Sprite时,可以将变化的属性放在其中,如平移,缩放,透明度等。一般雪碧图制作工具都会给出图片在大图中的坐标位置信息,可以添加解析到allSprites中去。
除此之外的还有颜色Color,混合模式blendMode,据此你可以对图片进行更多的操作。
5、绘制原始图集:drawAtlas
这个方法是
drawAtlas
的底层实现,其中变换列表,矩形域列表都转化为Float32List,颜色数组转化为Int32List,在使用方法上是一致的。
void _drawColorfulImage(Canvas canvas){
allSprites.add(Sprite(
position: Rect.fromLTWH(0, 325, 257, 166),
offset: Offset(0, 0),
alpha: 255,
rotation: 0));
allSprites.add(Sprite(
position: Rect.fromLTWH(0, 325, 257, 166),
offset: Offset(257, 130),
alpha: 255,
rotation: 0));
Float32List rectList = Float32List(allSprites.length * 4);
Float32List transformList = Float32List(allSprites.length * 4);
for (int i = 0; i < allSprites.length; i++) {
final Sprite sprite = allSprites[i];
rectList[i * 4 + 0] = sprite.position.left;
rectList[i * 4 + 1] = sprite.position.top;
rectList[i * 4 + 2] = sprite.position.right;
rectList[i * 4 + 3] = sprite.position.bottom;
final RSTransform transform = RSTransform.fromComponents(
rotation: sprite.rotation,
scale: 1.0,
anchorX: sprite.anchor.dx,
anchorY: sprite.anchor.dy,
translateX: sprite.offset!.dx,
translateY: sprite.offset!.dy,
);
transformList[i * 4 + 0] = transform.scos;
transformList[i * 4 + 1] = transform.ssin;
transformList[i * 4 + 2] = transform.tx;
transformList[i * 4 + 3] = transform.ty;
}
canvas.drawRawAtlas(image!, transformList, rectList, null, null, null, _paint);
}
2、 文字绘制
Flutter里面的文字绘制方法明显要麻烦很多,但属性多也就意味着
可定制性高
主要的绘制方法是通过drawParagraph
或TextPaint
.
1、drawParagraph绘制文字
通过
ParagraphBuilder
构造基本样式pushStyle
和添加文字addText
.builder.build()可以创建Paragraph对象,之后必须对layout限制区域,下面的蓝色区域是绘制的辅助,依次是左对齐、居中、右对齐。
void _drawTextWithParagraph(Canvas canvas,TextAlign textAlign) {
var builder = ui.ParagraphBuilder(ui.ParagraphStyle(
textAlign: textAlign,
fontSize: 40,
textDirection: TextDirection.ltr,
maxLines: 1,
));
builder.pushStyle(
ui.TextStyle(
color: Colors.black87, textBaseline: ui.TextBaseline.alphabetic),
);
builder.addText("Flutter Unit");
ui.Paragraph paragraph = builder.build();
paragraph.layout( ui.ParagraphConstraints(width: 300));
canvas.drawParagraph(paragraph, Offset(0, 0));
canvas.drawRect(Rect.fromLTRB(0, 0, 300, 40 ),
_paint..color = Colors.blue.withAlpha(33));
}
2、TextPainter绘制文字
TextPainter的绘制基本上就是对
drawParagraph
的封装,但是提供了很多的方法,使用起来更加简介一点,所以一般来说都会用TextPainter绘制文字。绘制先传入的TextPainter,然后进行layout布局,其中可以传入布局区域的最大和最小宽度,通过paint方法进行绘制。
void _drawTextPaint(Canvas canvas) {
var textPainter = TextPainter(
text: TextSpan(
text: 'Flutter Unit',
style: TextStyle(fontSize: 40,color: Colors.black)),
textAlign: TextAlign.center,
textDirection: TextDirection.ltr);
textPainter.layout(); // 进行布局
textPainter.paint(canvas, Offset.zero); // 进行绘制
}
最后
以上就是俊逸花瓣为你收集整理的Flutter绘制系列03---绘制图片文字2、 文字绘制的全部内容,希望文章能够帮你解决Flutter绘制系列03---绘制图片文字2、 文字绘制所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复