The timeline is often used in the front UI. Let’s take a look at the renderings:

Timeline features

1. The height in the list is uncertain, depending on the height of the item on the right. 2.

implementation

1. Set the border on the left by using the decoration attribute in the Container, so that the height of the timeline changes with item

      Center(
          child: Container(
        width: 100,
        height: 100,
        decoration: BoxDecoration(
        // set the border of the BoxDecoration. The border height is the height of the Container
          border: Border(left: BorderSide(color: Colors.red)),
          color: Color(0x11000000),)))Copy the code
The effect (the red line is the border to the left of the Container, which can be extended to timeline) :

Rewrite the paint method in BorderDirectional

So, the original Paint method in BorderDirectional, you can see that when you set different properties, you call different draw methods to do different things, so let’s do a new paint method to do the timeline

Parameters in the paint method

Canvas: This is the canvas. You can use this canvas to implement various effects. Rect: The size of Container

In our paint method, we use the UI design to draw circles and lines in the corresponding positions

  @override
  void paint(Canvas canvas, Rect rect, {TextDirection? textDirection, BoxShape shape = BoxShape.rectangle, BorderRadius? borderRadius}) {
    if(position ! =1) {
      canvas.drawLine(Offset(rect.left+margin + radius / 2, rect.top), Offset(rect.left +margin+ radius / 2, rect.bottom), _strokePaint());
      canvas.drawCircle(Offset(rect.left +margin+ radius / 2, rect.top + radius * 2), radius, _fillPaint());
      canvas.drawCircle(Offset(rect.left +margin+ radius / 2, rect.top + radius * 2), radius,_strokePaint());
    } else {
      canvas.drawLine(Offset(rect.left+margin + radius / 2, rect.top + radius * 2), Offset(rect.left+margin + radius / 2, rect.bottom), _strokePaint());
      canvas.drawCircle(Offset(rect.left+margin + radius / 2, rect.top + radius * 2), radius, _fillPaint());
      canvas.drawCircle(Offset(rect.left +margin+ radius / 2, rect.top + radius * 2), radius, _strokePaint());
      canvas.drawCircle(Offset(rect.left +margin+ radius / 2, rect.top + radius * 2), radius / 2, _strokePaint()); }}Copy the code

The final result

Complete code

class BorderTimeLine extends BorderDirectional {
  int position;

  BorderTimeLine(this.position);

  double radius = 10;
  double margin= 20; Paint _paint = Paint() .. color = Color(0xFFDDDDDD)
    ..strokeWidth = 1;

  @override
  void paint(Canvas canvas, Rect rect, {TextDirection? textDirection, BoxShape shape = BoxShape.rectangle, BorderRadius? borderRadius}) {
    if(position ! =0) {
      canvas.drawLine(Offset(rect.left+margin + radius / 2, rect.top), Offset(rect.left +margin+ radius / 2, rect.bottom), _strokePaint());
      canvas.drawCircle(Offset(rect.left +margin+ radius / 2, rect.top + radius * 2), radius, _fillPaint());
      canvas.drawCircle(Offset(rect.left +margin+ radius / 2, rect.top + radius * 2), radius,_strokePaint());
    } else {
      canvas.drawLine(Offset(rect.left+margin + radius / 2, rect.top + radius * 2), Offset(rect.left+margin + radius / 2, rect.bottom), _strokePaint());
      canvas.drawCircle(Offset(rect.left+margin + radius / 2, rect.top + radius * 2), radius, _fillPaint());
      canvas.drawCircle(Offset(rect.left +margin+ radius / 2, rect.top + radius * 2), radius, _strokePaint());
      canvas.drawCircle(Offset(rect.left +margin+ radius / 2, rect.top + radius * 2), radius / 2, _strokePaint());
    }
  }

  Paint _fillPaint(){
    _paint.color=Colors.white;
    _paint.style=PaintingStyle.fill;
    return _paint;
  }
  Paint _strokePaint(){
    _paint.color=Color(0xFFDDDDDD);
    _paint.style=PaintingStyle.stroke;
    return_paint; }}Copy the code

Used within an item of the ListView

  Widget _buildItem(BuildContext c, int i) {
    return Container(
        width: double.infinity,
        padding: EdgeInsets.symmetric(horizontal: 20),
        decoration: BoxDecoration(border: BorderTimeLine(i)),
        child: Padding(
          padding: const EdgeInsets.symmetric(horizontal: 20),
          child: Column(crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [
            Padding(padding: EdgeInsets.symmetric(vertical: 10)),
            Divider(color: Colors.grey.shade300, thickness: 40),
            Text("$i" * 6, style: TextStyle(color: Colors.black, fontSize: 16)),
            Text("abc\n" * Random().nextInt(10)),
            Padding(padding: EdgeInsets.symmetric(vertical: 10))))); }Copy the code

All code github