Custom UI series columns
Drawing capability of Canvas
- The Canvas provided by the Flutter system can draw regular geometric shapes and transform shapes
Regular geometry
Point drawPoints
void drawPoints(PointMode pointMode, List<Offset> points, Paint paint)
Copy the code
pointMode
: Drawing mode- PointMode.
points
Point, draw each point separately - PointMode.
lines
A line segment, every two points in a line segment - PointMode.
polygon
A line. All the points make a line
- PointMode.
points
: a collection of pointspaint
Brush:
_paint.strokeCap=StrokeCap.round;
Copy the code
When you set the strokeCap property of the brush to Round, you draw dots
void drawRawPoints(PointMode pointMode, Float32List points, Paint paint)
Copy the code
The drawRawPoints() method is basically similar to drawPoints() in that the set of points passed in is Float32List
- The sample code
void paint(Canvas canvas, Size size) { canvas.drawPoints(PointMode.points, [Offset(0, 0), Offset(30, 0), Offset(60, 0), Offset(90, 0)], _paint); _paint.strokeCap=StrokeCap.round; Canvas. Points(pointmode. points, [Offset(0, 50),Offset(30, 50),Offset(60, 50),Offset(90,50)], _paint); canvas.drawPoints(PointMode.lines, [Offset(0, 100), Offset(30, 100), Offset(60, 100),Offset(90, 100)], _paint); canvas.drawPoints(PointMode.polygon, [Offset(0, 150), Offset(30, 150), Offset(60, 150),Offset(90, 150)], _paint); Float32List points = Float32List. FromList ([0, 200, 30,200,60,200,90,200]); canvas.drawRawPoints(PointMode.points, points, _paint); }Copy the code
- Effect of the sample
Line drawLine
void drawLine(Offset p1, Offset p2, Paint paint)
Copy the code
- P1: the starting point
- P2: the end point
Set strokeWidth for paint to change the line width
- The sample code
Void paint(Canvas Canvas, Size Size) {Canvas. DrawLine (Offset. Zero, 100,0), _paint); _paint.strokeWidth=2; Canvas. DrawLine (Offset (0; seven), Offset (100), _paint); }Copy the code
- Effect of the sample
rectangular
/// rectangular
void drawRect(Rect rect, Paint paint)
/// The rounded rectangle
void drawRRect(RRect rrect, Paint paint)
/// Two rectangular clipped rings
void drawDRRect(RRect outer, RRect inner, Paint paint)
Copy the code
Set the style property for paint, and draw the border or fill mode
Rect has multiple named constructors
- The position of the rectangle is determined by the position of the four sides
Rect.fromLTRB(this.left, this.top, this.right, this.bottom) Copy the code
- Construct a rectangle from its left and top edges, its width, and its height
Rect.fromLTWH(double left, double top, double width, double height) Copy the code
- Construct a rectangle from its center point, width, and height
Rect.fromCenter({ required Offset center, required double width, required double height }) Copy the code
- Construct a rectangle enclosing the given circle
Rect.fromCircle({ required Offset center, required double radius }) Copy the code
- Construct a rectangle with the upper left and lower right points
Rect.fromPoints(Offset a, Offset b) Copy the code
- The sample code
@override
void paint(Canvas canvas, Size size) {
canvas.drawRect(Rect.fromCenter(center: Offset(30, 50), width: 60, height: 60), _paint);
_paint.style = PaintingStyle.stroke;
canvas.drawRect(Rect.fromCenter(center: Offset(100, 50), width: 60, height: 60), _paint);
canvas.drawRRect(RRect.fromRectXY(Rect.fromCenter(center: Offset(170, 50), width: 60, height: 60), 8, 8), _paint);
_paint.style = PaintingStyle.fill;
var outer = RRect.fromRectXY(Rect.fromCenter(center: Offset(240, 50), width: 60, height: 60), 0, 0);
var inner = RRect.fromRectXY(Rect.fromCenter(center: Offset(240, 50), width: 50, height: 50), 30, 30);
canvas.drawDRRect(outer, inner, _paint);
}
Copy the code
- Effect of the sample
Circle and arc
void drawCircle(Offset centre, double radius, Paint paint)
Copy the code
Methods like drawCircle draw round
centre
Center:radius
Radius of:
void drawOval(Rect rect, Paint paint)
Copy the code
Draw the ellipse
rect
The range of the ellipse, the ellipse is the tangent ellipse of this rectangle
void drawArc(Rect rect, double startAngle, double sweepAngle, bool useCenter, Paint paint)
Copy the code
Arcs and sectors
rect
: The range of the ellipse in which the arc is locatedstartAngle
: Starting Angle, in radian units, that is, 2*π=360°. 0 is the right-most horizontal direction clockwise.sweepAngle
: Arc The arc of a lineuseCenter
: sector when true, arc when false
- The sample code
@override
void paint(Canvas canvas, Size size) {
canvas.drawCircle(Offset(50, 50), 50, _paint);
canvas.drawOval(Rect.fromLTRB(130, 0, 300, 100), _paint);
canvas.drawArc(Rect.fromLTWH(0, 120, 150, 100), 0, pi/2, false, _paint);
canvas.drawArc(Rect.fromLTWH(160, 120, 150, 150), 3*pi/2, pi/3, true, _paint);
}
Copy the code
- Effect of the sample
Image drawImage
void drawImage(Image image, Offset offset, Paint paint)
Copy the code
image
This is not a Wdiget image, but a dart. UI imageoffset
: Position in the upper left corner of the picture
Method to get uI.image
Future<void> loadImage() async { image = await _loadImageByProvider(AssetImage("images/coupons.png")); setState(() {}); } Future<ui.Image> _loadImageByProvider(ImageProvider provider, {ImageConfiguration config = ImageConfiguration.empty}) async { Completer<ui.Image> completer = Completer<ui.Image>(); late ImageStreamListener listener; ImageStream stream = provider.resolve(config); listener = ImageStreamListener((ImageInfo frame, bool sync) { final ui.Image image = frame.image; completer.complete(image); stream.removeListener(listener); }); stream.addListener(listener); return completer.future; } Copy the code
canvas.drawImageRect(image, src, dst, paint)
Copy the code
Select part of the image to the target region
- The sample code
@override void paint(Canvas canvas, Size size) { if (image ! = null) {// Draw canvas. DrawImage (image! , Offset.zero, _paint); Var SRC = rect.fromltwh (0, 0, image?.width. ToDouble ()?? Sie.width, image?.height.toDouble() ?? size.height); var dst = Rect.fromLTWH(150, 0, 70, 70); canvas.drawImageRect(image! , src, dst, _paint); }}Copy the code
- Example effects (Set the size of the target area to allow the image to be zoomed in and out)
void drawImageNine(Image image, Rect center, Rect dst, Paint paint)
Copy the code
Draw an image center: stretchable or compressed area DST: the area on the canvas
The image is segmented by drawing two horizontal and two vertical lines. The image is drawn into nine parts, where the center parameter describes the rectangle formed by the four points where these four lines intersect each other. When stretched or compressed, the four angles remain the same, and the horizontal and vertical directions corresponding to the center change
- The sample code
@override
void paint(Canvas canvas, Size size) {
if (image != null) {
var center = Rect.fromLTWH(50, 50, 20, 20);
var dst = Rect.fromLTWH(0, 0, 128*2, 128);
canvas.drawImageNine(image!, center, dst, _paint);
canvas.drawImage(image!, Offset(0,100), _paint);
}
}
Copy the code
- Effect of the sample
Colors and Shadows
void drawColor(Color color, BlendMode blendMode)
Copy the code
Color background, blendMode: color blending mode
void drawShadow(Path path, Color color, double elevation, bool transparentOccluder)
Copy the code
path
: Shadow pathcolor
: Shadow colorelevation
: Height of the shadowtransparentOccluder
“: Official document translation meansWhether the occluding object is transparent
. Personally, because shadows are created when a light source is blocked above the canvas,transparentOccluder
为false
When, the shield is opaque.
- The sample code
@override void paint(Canvas canvas, Size size) { Path path = Path(); var rect = Rect.fromLTWH(10, 10, 150, 45); path.addRect(rect); canvas.drawShadow(path, Colors.red, 5, false); Paint paint = Paint().. color = Colors.red; canvas.drawRect(rect, paint); }Copy the code
- Effect of the sample
Path
Path Path is an important and commonly used tool in Canvas drawing ability. It is composed of multiple complex one-dimensional paths, including points, lines, arcs and Bezier curves, which can be open or closed. The method of adding subpaths to Path is similar to the method of drawing on Canvas above, which mainly includes points, lines, rectangles, circles and arcs.
Some relatively simple apis
// Move the brush to the specified position
void moveTo(double x, double y)
// Connect a line from the current position to the specified position
void lineTo(double x, double y)
// Add a rectangle to path
void addRect(Rect rect)
// Add rounded rectangles
void addRRect(RRect rrect)
// Add an ellipse to path, if Rect is a square, then add a circle
void addOval(Rect oval)
// Add an arc to path in radians
void addArc(Rect oval, double startAngle, double sweepAngle)
// Add some points to the path, which will be connected to a line segment. [close] closes or not. If true, the last point is connected to the first point
void addPolygon(List<Offset> points, bool close)
// Add another path to the current path
void addPath(Path path, Offset offset, {Float64List? matrix4})
// Reset Path to restore Path to its original state with the current point as the starting point
void reset()
// Close the image
void close()
Copy the code
- The sample code
@override void paint(Canvas canvas, Size size) { var path = Path(); Path. MoveTo (10, 10); path.lineTo(100, 10); path.lineTo(100, 60); path.lineTo(10, 60); // Finally the line will be drawn from the current position to the starting point path.close(); canvas.drawPath(path, _paint); }Copy the code
arc
void arcTo(Rect rect, double startAngle, double sweepAngle, bool forceMoveTo)
Copy the code
So if you draw an arc, forceMoveTo means when you draw that arc, do you drag the pen to the starting point or do you lift the pen to the starting point
@override void paint(Canvas canvas, Size size) { var path = Path(); Path. The moveTo (0, 0); Path. The lineTo (100, 0); path.arcTo(Rect.fromLTWH(0, 0, 100, 100), 0, pi, true); canvas.drawPath(path, _paint); }Copy the code
Bessel curve
// Second order curve
void conicTo(double x1, double y1, double x2, double y2, double weight)
Copy the code
Plot bezier curves
x1
andy1
Control points:x2
andy2
: Target point of the curveweight
: Weight, greater than 1, then the curve is hyperbola; If the weight is equal to 1, it is a parabola; If it’s less than 1, it’s an ellipse
void cubicTo(double x1, double y1, double x2, double y2, double x3, double y3)
Copy the code
Third order Bezier curve
x1
andy1
: Control point 1x2
andy2
: Control point 2x3
andy3
: Target point of the curve
- The sample code
@override void paint(Canvas canvas, Size size) { var path = Path(); path.moveTo(80, 40); Path. ConicTo (160, 120, 240, 40, 1); canvas.drawPath(path, _paint); var path2 = Path(); path2.moveTo(80, 160); path2.cubicTo(120, 200, 160, 100, 240, 160); canvas.drawPath(path2, _paint); }Copy the code
- Effect of the sample
Relative coordinates
void relativeMoveTo(double dx, double dy)
void relativeLineTo(double dx, double dy)
Copy the code
Relative *** relative to the current position.
The boundary of the path
Rect getBounds()
Copy the code
Gets the path boundary range and returns a Rect.
- The sample code
@override void paint(Canvas canvas, Size size) { var path2 = Path(); path2.moveTo(80, 80); path2.lineTo(160, 80); path2.arcTo(Rect.fromLTWH(160, 80, 80, 80), 0, pi, false); path2.lineTo(0, 80); path2.close(); canvas.drawPath(path2, _paint); // Path bounds var bounds = path2.getbounds (); _paint.color=Colors.black; canvas.drawRect(bounds, _paint); }Copy the code
- Effect of the sample
PathMetric
PathMetrics computeMetrics({bool forceClosed = false})
Copy the code
Returns a collection of PathMetric objects with changed paths
PathMetric is a tool for measuring and extracting paths, and you can get a lot of information about your path
- PathMetric.
length
: Indicates the total length of the path- PathMetric.
isClosed
: Indicates whether the current path is a closed path- PathMetric.
contourIndex
: Indicates the index of the current path- Tangent?
getTangentForOffset(double distance)
: Returns information about a point with a point length.
For example, the getTangentForOffset (50) method of a path with length =100 computes the position and Angle of the point with length 50. The Angle is the Angle between the tangent of the point and the positive direction of the x axis.
- The sample code
@override void paint(Canvas canvas, Size size) { var path = Path(); path.moveTo(0, 0); path.addOval(Rect.fromLTWH(0, 0, 160, 160)); canvas.drawPath(path, _paint); PathMetric pathMetric = path.computeMetrics().first; print(pathMetric.length); Print (pathmetry.isclosed); // true print(pathMetric.contourIndex); // 0 var tangentForOffset = pathMetric.getTangentForOffset(100); _paint.strokeWidth=10; canvas.drawPoints(ui.PointMode.points, [tangentForOffset!.position], _paint); print(tangentForOffset.angle); }Copy the code
- Effect of the sample
Canvas out
void clipPath(Path path, {bool doAntiAlias = true})
void clipRect(Rect rect, { ClipOp clipOp = ClipOp.intersect, bool doAntiAlias = true })
void clipRRect(RRect rrect, {bool doAntiAlias = true})
Copy the code
Canvas clipping, clipping the specified part and drawing over the rest
-
ClipOp: clipop. difference, minus the target region; Clipop. intersect preserves the target area
-
DoAntiAlias: Whether anti-aliasing effect
-
The sample code
@override void paint(Canvas canvas, Size size) { canvas.clipRect(Rect.fromLTWH(50, 50, 50, 50), clipOp: ui.ClipOp.difference); canvas.drawImageRect( image! , Rect.fromLTWH(0, 0, image! .width.toDouble(), image! .height.toDouble()), Rect.fromLTWH(0, 0, 200, 200), _paint, ); }Copy the code
- Effect of the sample
The commutation of the Canvas
Canvas provides four transformation operations: displacement, rotation, scaling, and tangent, whose effects are similar to the Transform component provided by the system. Before you get familiar with these four transformation operations, you should first understand the coordinate system in Flutter.
Coordinate system
The coordinate system in a Flutter is the origin of the top left corner of the current canvas, the X-axis is positive to the left, and the Y-axis is positive to the downward. The Angle is in radians, 0 degrees to the right of the horizontal position from the origin, clockwise. PI is horizontal to the left of the origin.
The displacement of the translate
void translate(double dx, double dy)
Copy the code
Move the canvas origin to the specified position, dx and dy can be negative
The zoom scale
void scale(double sx, [double? sy])
Copy the code
For scaling operations,sx and SY are scaling scales in the X and y directions, respectively. If SY is not specified,sx will be used for scaling in both directions. Sx and SY can be negative, and negative values will have the effect of antirotation.
As shown in the figure, black is the original coordinate system, and red is the transformed coordinate system.
Rotate the rotate
void rotate(double radians)
Copy the code
Rotate the canvas with the origin as the center, radians: rotation Angle, radians, that is, PI =180º
As shown in the figure, black is the original coordinate system, and red is the transformed coordinate system.
Oblique skew
void skew(double sx, double sy)
Copy the code
Sx and SY are the tangent values of x and y axes, and the values are the tan values of the trigonometric function, that is, the tangent value of 45 degrees is 1.
As shown in the figure, black is the original coordinate system, and red is the transformed coordinate system.
The save and restore
Saves a copy of the current transform and clip on the save stack.
That is, there is a stack that holds the state of the canvas, and when called save, the current canvas is saved to the stack. When restore is called, the canvas state is removed from the stack. Since it is stored on a stack, the Canvas save and restore have the following features
- If they come in pairs, there is one
save
You need to have onerestore
- Because it is stored in the stack, it has the characteristics of the stack – last in first out, that is, there are multiple
save
, the callrestore
Will start from the last onesave
Start.
- The sample code
@override void paint(Canvas Canvas, Size Size) {// Coordinates _canvasCoordinates(Canvas); DrawRect (Offset. Zero & Size(80, 50), _paint); // Save state 1 canvas.save(); canvas.rotate(pi); canvas.translate(0, 20); canvas.skew(0, 1); _paint.color = Colors.red; canvas.drawRect(Offset.zero & Size(80, 50), _paint); // Restore state 1 canvas.restore(); Canvas. Translate (-100, 0); canvas. Translate (-100, 0); _paint.color = Colors.green; canvas.drawRect(Offset.zero & Size(80, 50), _paint); }Copy the code
- Effect of the sample
conclusion
Canvas has very powerful functions, and THERE are some APIS that I am vague about, which will be supplemented gradually in the future. The next article will use some common UI requirements in our development to show the powerful functions of Canvas with actual code.