For this case, I think ListView.separated
will be the better choice. Above answer doesn't work after changing screen width.
We need to get the width of Chapter X
and circle (having radius 24). To get the Text
size, we will use this.
Size _textSize(String text, TextStyle style) {
final TextPainter textPainter = TextPainter(
text: TextSpan(text: text, style: style),
maxLines: 1,
textDirection: TextDirection.ltr)
..layout(minWidth: 0, maxWidth: double.infinity);
return textPainter.size;
}
You can check original question and answer of getting text size.
To draw lines I am using CustomPainter
.
class DivPainter extends CustomPainter {
int index;
DivPainter({required this.index});
@override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = Colors.grey
..style = PaintingStyle.stroke
..strokeWidth = 5;
final path1 = Path()
..moveTo(0, 24)
..lineTo(size.width, size.height + 24);
final path2 = Path()
..moveTo(0, size.height + 24)
..lineTo(size.width, 24);
index.isEven
? canvas.drawPath(path1, paint)
: canvas.drawPath(path2, paint);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}
I am using ListView.builder
with Stack[customPaint, widget]
for this solution
LayoutBuilder listview() {
return LayoutBuilder(
builder: (context, constraints) => Container(
color: Colors.cyanAccent.withOpacity(.3),
width: constraints.maxWidth,
child: ListView.builder(
itemCount: itemLength,
itemBuilder: (context, index) {
final textWidth = _textSize("Chapter $index", textStyle).width;
final painterWidth = constraints.maxWidth -
((textWidth + 24) *
2); //24 for CircleAvatar, contains boths side
return SizedBox(
height: index == itemLength - 1 ? 24 * 2 : 100 + 24,
width: constraints.maxWidth,
child: Stack(
children: [
/// skip render for last item
if (index != itemLength - 1)
Align(
alignment: Alignment.center,
child: SizedBox(
width: painterWidth,
height: height,
child: CustomPaint(
painter: DivPainter(index: index),
),
),
),
Row(
mainAxisAlignment: index.isEven
? MainAxisAlignment.start
: MainAxisAlignment.end,
children: [
if (index.isEven)
Text(
"Chapter $index",
style: textStyle,
),
const CircleAvatar(radius: 24),
if (index.isOdd)
Text(
"Chapter $index",
style: textStyle,
),
],
),
],
),
);
},
),
),
);
}

make sure of screenWidth > lineHeight*2, you can replace 100
with constraints
dynamic value
You can check full snippet and run on dartPad.
Also, if you are ok with not having precious positioning, you can use ListView.separate
. You can find that inside dartPad, Also make sure to remove extra spacing on Path
. You can simply replace path with drawLine
.