The Flutter Canvas will learn as a series of original portals:
- Learn the basics of Flutter Canvas
- Drawing of Flutter Canvas learning
- Flutter Canvas learning words and pictures
preface
In general UI framework, text and picture drawing are more complicated, so I will explain it in a separate article.
Paragraph
void drawParagraph(Paragraph paragraph, Offset offset)
Paragraph is a class that is used to draw text in a Flutter. All the text in a Flutter is drawn through it, including the input box. This shows its power.
A Paragraph is a class with no constructor; it simply provides a host for the final rendering. What we really need to deal with is a class that ParagraphBuilder.
The ParagraphBuilder class takes one parameter, which is a ParagraphStyle class that sets basic font styles, such as font direction, alignment, font thickness, and so on. Next, we draw text in a few steps
First, generate ParagraphStyle class
import 'dart:ui' as ui;
final paragraphStyle = ui.ParagraphStyle(
// Font orientation. Some languages are formatted from right to left
textDirection: TextDirection.ltr,
// Font alignment
textAlign: TextAlign.justify,
fontSize: 14,
maxLines: 2.// Display the prompt when the font size exceeds
ellipsis: '... ',
fontWeight: FontWeight.bold,
fontStyle: FontStyle.italic,
height: 5.// Whether the height applies to the top and bottom of the font when we set [textstyle.height]
textHeightBehavior:
TextHeightBehavior(applyHeightToFirstAscent: true,applyHeightToLastDescent: true));
Copy the code
Second, you generate ParagraphBuilder based on ParagraphStyle
final paragraphBuilder = ui.ParagraphBuilder(paragraphStyle);
Copy the code
Third, add text. The ParagraphBuilder class has an addText method specifically for receiving text
paragraphBuilder.addText('JSShou learning Canvas');
Copy the code
Step 4, retrieve the Paragraph class through build
var paragraph = paragraphBuilder.build();
Copy the code
Step 5: Layout according to the width and height
paragraph.layout(ui.ParagraphConstraints(width: 300));
Copy the code
Step 6: Paint
canvas.drawParagraph(paragraph, Offset(50.50));
Copy the code
The whole code is as follows
/ / the first step
final paragraphStyle = ui.ParagraphStyle(
// Font orientation. Some languages are formatted from right to left
textDirection: TextDirection.ltr,
// Font alignment
textAlign: TextAlign.justify,
fontSize: 14,
maxLines: 2.// Display the prompt when the font size exceeds
ellipsis: '... ',
fontWeight: FontWeight.bold,
fontStyle: FontStyle.italic,
height: 5.// Whether the height applies to the top and bottom of the font when we set [textstyle.height]
textHeightBehavior:
TextHeightBehavior(applyHeightToFirstAscent: true,applyHeightToLastDescent: true));
// Step 2 and step 3
finalparagraphBuilder = ui.ParagraphBuilder(paragraphStyle) .. addText('ParagraphBuilder class takes one parameter, which is a ParagraphStyle class that sets basic font styles, such as font direction, alignment, font thickness, and so on. Let's draw the text in a few steps. ');
/ / step 4
var paragraph = paragraphBuilder.build();
/ / step 5
paragraph.layout(ui.ParagraphConstraints(width: 300));
// Draw an auxiliary rectangle (you can use paragraph. Width and paragraph. Height to get the width and height of the drawn text)
canvas.drawRect(
Rect.fromLTRB(50.50.50 + paragraph.width, 50 + paragraph.height),
paint);
/ / step 6
canvas.drawParagraph(paragraph, Offset(50.50));
Copy the code
The effect is as follows:
TextPainter
Paragraph, I have to say TextPainter. TextPainter is encapsulated by Paragraph, which provides more power than Paragraph
- By passing in
TextSpan
To achieve a variety of different effects of fonts to support rich text - Don’t like
Paragraph
You must set a width, which can be used without initializing the widthTextPainter.width
To get the actual render width (actuallyParagraph
It can be done, but it encapsulates a layer of development thinking that is closer to us.)
It is also simple to use
var textPainter = TextPainter(
text: TextSpan(
text:
"Rich text can be supported by a variety of fonts with different effects.",
style: TextStyle(color: Colors.white,fontSize: 20)),
textDirection: TextDirection.rtl,
textWidthBasis: TextWidthBasis.longestLine,
maxLines: 2.)// You can pass minWidth, maxWidth to limit its width. If not, the text will be drawn on a single line
..layout();
var startOffset = 50.0;
TextPainter. Width and textPainter. Height can be used to get the width of the text drawn before the text is drawn
canvas.drawRect(
Rect.fromLTRB(startOffset, startOffset, startOffset + textPainter.width,
startOffset + textPainter.height),
paint);
textPainter.paint(canvas, Offset(startOffset, startOffset));
Copy the code
drawImage
void drawImage(Image image, Offset offset, Paint paint)
We can draw an Image by drawImage. The Image here is not our usual Image, it is the Image in the Dart: UI library, which holds some basic information about the Image and interacts directly with the engine.
To use this method, you need to load an image. There are many ways to load an image, but I’ll show you one way
load('assets/test.png');
// ...
Future<ui.Image> load(String asset) async {
ByteData data = await rootBundle.load(asset);
ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List(),targetWidth: 300,targetHeight: 300);
ui.FrameInfo fi = await codec.getNextFrame();
return fi.image;
}
Copy the code
Since image loading is an asynchronous process, you can’t load them in the paint method of CustomPaint (because canvas is disposed after paint, and Object has been disposed if you use canvas after asynchronous method), You need to use a StatefulWidget externally that passes the Image you get into the CustomPaint after loading. At this point, use Canvas. drawImage to load.
drawImageRect
void drawImageRect(Image image, Rect src, Rect dst, Paint paint)
- SRC: Capture an image area with the starting point relative to the upper left corner of the image
- DST: Draw an area on the canvas to draw the captured image. The image may be pulled up
// Draw the original image
canvas.drawImage(image, Offset(50.50), paint);
// Image area
Rect rect = Rect.fromCenter(
center: Offset(image.width / 2, image.height / 2),
width: image.width / 2,
height: image.height / 2);
// Draw the auxiliary line, move it down and right 50, because the original is relative to Offset(50,50).
canvas.drawRect(rect.shift(Offset(50.50)), paint);
// go
canvas.drawImageRect(
image,
rect,
Rect.fromLTWH(50.500.100.100),
paint);
Copy the code
drawImageNine
void drawImageNine(Image image, Rect center, Rect dst, Paint paint)
This method is similar to the.9 image in Android, where certain areas are not distorted when the image is stretched, and real areas can be drawn by ourselves.
canvas.drawImage(image, Offset(50.50), paint);
Rect rect = Rect.fromCenter(
center: Offset(image.width / 2, image.height / 2),
width: image.width / 2,
height: image.height / 2);
canvas.drawRect(rect.shift(Offset(50.50)), paint);
Rect dst = Rect.fromLTWH(50.500.200.200);
canvas.drawImageNine(image, rect, dst, paint);
Copy the code
If we change the DST, which is the image drawing area
Rect dst = Rect.fromLTWH(50.500.400.200);
Copy the code
You are smart enough to have found that the image is stretched and compressed in a certain way. The blue area of the original image above is the position that can be compressed and stretched, and the upper, lower, left and right parts of the blue area also exist the position that can be stretched, and the four corners will remain unchanged without distortion.
drawPicture
This method is drawn by passing in an instance of a Picture, which is constructed by PictureRecorder.
// Start recording Picture
ui.PictureRecorder recorder = ui.PictureRecorder();
Canvas canvas = new Canvas(recorder);
// Call the Canvas drawing interface to draw a circle
canvas.drawCircle(
Offset(200.200), 100, Paint().. color = Colors.yellow);// 绘制结束,生成Picture
Picture picture = recorder.endRecording();
Copy the code
“Picture” does not refer to our traditional Picture, Picture correlation is expressed by Image, Picture is drawn by any graph (drawLine, drawRect, etc.). The above is just the simplest example of creating a Picture. We create a Canvas object to record the drawing data, and call Recorder. EndRecording to end the recording and return a Picture object. As a special note, the Canvas provides the drawPicture method and does not expect us to use PictureRecorder to record and draw the UI(in fact, if we did this in paint, we would get an error. CustomPaint provides a Canvas object, which does not require new), and we can use this method when we get a Picture object somewhere else. So we need to execute the above code in the StatefulWidget and pass the resulting Picture object into CustomPaint for drawing.
class MyCanvas extends CustomPainter {
final ui.Picture picture;
MyCanvas(this.picture);
@override
void paint(Canvas canvas, Size size) async {
if(picture ! =null) canvas.drawPicture(picture);
}
/ /...
}
Copy the code
The next chapter will introduce Canvas graph transformation, such as rotation, translation, zooming, etc. If you are interested, please pay attention
- zhihu
- Personal blog
- GitHub