Custom UI series columns
Preface – Timeline
Besides drawing charts, Canvas can also be used for other purposes. For example, the effect of timeline timeline can be realized after customized drawing. The usual timeline has the following characteristics:
- Is a list, and the item of the listhighlyNot fixed
- One side of the list is marked with axes
There are many ways to realize the time axis in Web, Android and IOS. This article will use the decoration property of Container on Flutter to realize the effect of the time axis by drawing on Canvas.
Container
Container is one of the most commonly used Flutter components. Its decoration allows you to create a variety of borders for the Container.
Container(
width: 100,
height: 150,
decoration: BoxDecoration(
border: Border(left: BorderSide(color: Colors.blue, width: 2)),
color: Colors.grey.shade400,
),
);
Copy the code
As shown in figure 3, set only the left border for the Container. Because the border height follows the Container, which fits the timeline requirement, we can use the border as the timeline and use the Container to implement the item.
BoxDecoration
The border in BoxDecoration is the border property. Usually we use border or BorderDirectional, a subclass of BoxBorder. BorderDirectional, for example, in addition to a few property Settings, there’s a paint method, which is a method that draws borders
void paint(
Canvas canvas,
Rect rect, {
TextDirection? textDirection,
BoxShape shape = BoxShape.rectangle,
BorderRadius? borderRadius,
}) {
if (isUniform) {
switch (top.style) {
case BorderStyle.none:
return;
case BorderStyle.solid:
switch (shape) {
case BoxShape.circle:
assert(borderRadius == null.'A borderRadius can only be given for rectangular boxes.');
BoxBorder._paintUniformBorderWithCircle(canvas, rect, top);
break;
case BoxShape.rectangle:
if(borderRadius ! =null) {
BoxBorder._paintUniformBorderWithRadius(canvas, rect, top, borderRadius);
return;
}
BoxBorder._paintUniformBorderWithRectangle(canvas, rect, top);
break;
}
return; }}// omit more....
}
Copy the code
The BorderDirectional Paint method calls the corresponding draw method to draw different border effects based on the various properties we set. This will eventually be called by the _BoxDecorationPainter object generated in the BorderDirectional createBoxPainter method
class BoxDecoration extends Decoration {
// omit more....
@override
BoxPainter createBoxPainter([ VoidCallback? onChanged ]) {
assert(onChanged ! =null || image == null);
return _BoxDecorationPainter(this, onChanged); }}class _BoxDecorationPainter extends BoxPainter {
// omit more....
/// Paint the box decoration into the given location on the given canvas.
@override
void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
// omit more....
// This is where the paint on the Border is called_decoration.border? .paint( canvas, rect, shape: _decoration.shape, borderRadius: _decoration.borderRadiusas BorderRadius?,
textDirection: configuration.textDirection,
);
}
}
Copy the code
From this, we can inherit BoxBorder and rewrite its paint method, using the Canvas provided by the paint method to draw the effect we want.
Inheritance override of BoxBorder
Parameter to the paint method in BoxBorder
- Canvas, canvas
- Rect: Canvas scope
- TextDirection: indicates the textDirection
Go straight to code
class TimeLineBoxBorder extends BoxBorder {
@override
BorderSide get bottom => BorderSide.none;
@override
BorderSide get top => BorderSide.none;
@override
ShapeBorder scale(double t) => this;
@override
EdgeInsetsGeometry get dimensions => EdgeInsetsGeometry.infinity;
@override
bool get isUniform => false;
@override
voidpaint(Canvas canvas, Rect rect, {TextDirection? textDirection, BoxShape shape = BoxShape.rectangle, BorderRadius? borderRadius}) { canvas.drawLine( Offset(rect.left, rect.top), Offset(rect.left, rect.bottom), paintLine, ); canvas.drawPoints( PointMode.lines, _points(rect), paintPoint, ); }}Copy the code
Set the decoration property of the Container to BoxDecoration and the border to our custom TimeLineBoxBorder.
Container(
width: 100,
height: 100,
decoration: BoxDecoration(border: TimeLineBoxBorder(), color: Colors.grey.shade400),
);
Copy the code
Final effect:
In this way, we implement the custom border by re-painting the BoxBorder. Apply the Container to the ListView and it will look like the timeline effect.
Write in the last
In addition to overwriting the border, we can also overwrite the createBoxPainter method of BoxDecoration to define a BoxPainter to implement more Container backgrounds and decorative borders.
Attached are some renderings: