Draw a simple income – expense progress chart today; The general effect is a simple presentation of content in two trapezoids; In order to improve the reusability, the following rules are preset for the side dishes;
- Display the corresponding size in proportion to the left and right sides, and pay attention to the large proportion of abnormalities
- You can customize the left and right content colors
- You can customize the left and right text colors
- The left and right sides support fill and border styles
ACEProgressPainter
Xiaocai determined the set rules, and then came the practical operation, mainly drawing by Canvas, which is divided into drawing graphics and drawing text.
Canvas. DrawPath Draws a trapezoid (triangle)
1. Draw a trapezoid to scale
The side dish preset a left reminding ratio, which is calculated based on the overall width of the screen and located on the trapezoid middle line, where the trapezoid Angle preset is 45 degrees, so that the trapezoid position can be calculated according to the height of the trapezoid; The right trapezoid is similar to the left trapezoid. Note the spaceWidth between the trapezoid and the left trapezoid.
// Left canvas. DrawPath (Path().. MoveTo (_spaceWidth * 0.5 + _strokeWidth, _strokeWidth * 0.5).. LineTo (_spaceWidth * 0.5 + _strokeWidth, _height - _strokeWidth * 0.5).. LineTo (size.width * leftProgress + _height * 0.5 - _spaceWidth * SQRT (2) - _strokeWidth * SQRT (2), _height - _strokeWidth * 0.5).. LineTo (size.width * leftProgress + _height * 0.5 - _spaceWidth * SQRT (2) - _strokeWidth * SQRT (2) - _height + _strokeWidth, _strokeWidth * 0.5).. LineTo (_spaceWidth * 0.5 + _strokeWidth, _strokeWidth * 0.5).. close(), _paint.. color = leftColor ?? _kProLeftColor); // Right canvas. DrawPath (Path().. MoveTo (sie.width - _kProPaddingWidth - _strokeWidth * 0.5, Offset.zero.dy).. LineTo (size.width - _kProPaddingWidth - _strokeWidth * 0.5, _height).. LineTo (size.width * leftProgress + _height * 0.5 + _spaceWidth * 0.5 + _strokeWidth, _height).. LineTo (size.width * leftProgress - _height * 0.5 + _spaceWidth * 0.5 + _strokeWidth, offset.zero.dy).. LineTo (size.width - _kProPaddingWidth - _strokeWidth * 0.5, Offset.zero.dy).. close(), _paint.. color = rightColor ?? _kProRightColor);Copy the code
2. Abnormal ratio
If the scale is too small or too large, the small dish plans to show a fixed triangle, and in this case do not draw text;
// left if ((sie.width * leftProgress + _height * 0.5 - _spaceWidth * 0.5 - _strokeWidth) <= _height) {_leftpath.lineto ( Height + _kProPaddingWidth + _strokeWidth * 0.5, _height); } else if ((sie.width * leftProgress + _height * 0.5) >= sie.width - _height) {_leftpath.lineto (sie.width - _height) _spaceWidth - _strokeWidth * 2 - _kProPaddingWidth, _height); _leftPath.lineTo( size.width - _spaceWidth - _strokeWidth * 2 - _height - _kProPaddingWidth, Offset.zero.dy); } else {_leftpath. lineTo(size.width * leftProgress + _height * 0.5 - _spaceWidth * 0.5 - _strokeWidth, _height); LineTo (size.width * leftProgress - _height * 0.5 - _spaceWidth * 0.5 - _strokeWidth, offset.zero. } // if ((sie.width * leftProgress + _height * 0.5 - _spaceWidth * 0.5 - _strokeWidth) <= _height) { _rightPath.lineTo( _height + _spaceWidth + _strokeWidth * 2 + _kProPaddingWidth, _height); _rightPath.lineTo( _spaceWidth + _strokeWidth * 2 + _kProPaddingWidth, Offset.zero.dy); } else if ((sie.width * leftProgress + _height * 0.5) >= sie.width - _height) {_rightPath.lineto (sie.width - _height - _strokeWidth * 0.5 - _kProPaddingWidth, Offset.zero.dy); } else {_rightpath. lineTo(sie.width * leftProgress + _height * 0.5 + _spaceWidth * 0.5 + _strokeWidth, _height); Rightpath. lineTo(size.width * leftProgress - _height * 0.5 + _spaceWidth * 0.5 + _strokeWidth, offset.zero.dy); }Copy the code
3. Check whether to fill it
Paint().style = paintingstyle.fill/stroke. If strokeWidth is set to Path, the strokeWidth must be within the border. If strokeWidth is set to Path, the strokeWidth must be within the border. The smaller the filling range is, the larger the overall graph will be drawn, so the calculation needs to be based on the middle position of the border. For small dishes, in order to avoid insufficient filling range, set paintingstyle. fill to reduce the border thickness to 0.5;
_paint = _paint
..strokeWidth = (isFill == null || isFill == false) ? _strokeWidth : 0.5
..style = (isFill == null || isFill == false) ? PaintingStyle.stroke : PaintingStyle.fill;
Copy the code
Canvas.drawParagraph Draws the text
The key to drawParagraph text rendering is to process text attributes and positioning;
1. Text on the left
The range of text needs to be in a trapezoid and cannot go beyond its trapezoid length, so by calculating, you set ParagraphConstraints(width: _leftTextWidth) to a word width range; Sets text attributes, including color, size, and whether ParagraphStyle goes to a ParagraphStyle; Finally, the canvas.drawParagraph is used to set the starting position of the text (the paragraph height can be obtained).
If (_leftTextWidth > 0.0) {Color _leftColor; if (leftTextColor ! = null) { _leftColor = leftTextColor; } else if (isFill ! = null && this.isFill == true) { _leftColor = Colors.white; } else if (leftColor ! = null) { _leftColor = leftColor; } else { _leftColor = _kProLeftColor; } ParagraphBuilder _pb = ParagraphBuilder(ParagraphStyle( textAlign: TextAlign.left, fontWeight: FontWeight.w500, fontStyle: FontStyle.normal, maxLines: 1, ellipsis: '... ', fontSize: 16)) .. pushStyle(ui.TextStyle(color: _leftColor)) .. addText(leftText); ParagraphConstraints pc = ParagraphConstraints(width: _leftTextWidth); Paragraph paragraph = _pb.build().. layout(pc); Canvas. drawParagraph(paragraph, Offset(_kProPaddingWidth * 2 + _strokeWidth, _height * 0.5 - paragraph. }Copy the code
2. Text on the right
The text on the right side is slightly more complex than that on the left side. First, you set word paragraphstyle. textAlign to the right, and then pay attention to the starting position of the text drawn on the right side, the border width and the space between two trapezoidal spacewidthwhen calculating the width of the text on the right. The most important thing is to have space on the right side, side dishes add placeholders through the addPlaceholder;
Note: When the distance between the starting position and the right side of the screen is smaller than the set width, the placeholders work but the overall range is outside the screen, so notice that the starting position and the text paragraph width are calculated correctly;
If (_rightTextWidth > 0.0) {Color _rightColor; if (rightTextColor ! = null) { _rightColor = rightTextColor; } else if (isFill ! = null && this.isFill == true) { _rightColor = Colors.white; } else if (rightColor ! = null) { _rightColor = rightColor; } else { _rightColor = _kProRightColor; } ParagraphBuilder _pb = ParagraphBuilder(ParagraphStyle( textAlign: TextAlign.right, fontWeight: FontWeight.w500, fontStyle: FontStyle.normal, maxLines: 1, ellipsis: '... ', fontSize: 16)) .. pushStyle(ui.TextStyle(color: _rightColor)) .. addText(rightText) .. addPlaceholder(_kProPaddingWidth * 2 + _strokeWidth, Offset.zero.dy, PlaceholderAlignment.middle); ParagraphConstraints pc = ParagraphConstraints(width: _rightTextWidth); Paragraph paragraph = _pb.build().. layout(pc); Paragraph(paragraph, Offset(_rightStartWidth, _height * 0.5 - paragraph. Height * 0.5)); }Copy the code
ACEProgressPainter case source code
The progress comparison diagram is mainly drawn by Canvas, and widgets are not individually encapsulated. Among them, drawParagraph has many hidden familiar widgets that have not been tried. If there are mistakes, please give more guidance!
Source: Little Monk A Ce