这大概是flutter最简单的时间线了吧 maybe ,利用stack的特性 摒弃传统的计算逻辑
import 'package:flutter/material.dart';
typedef IndexedTimeItemBuilder = InfoItem Function(
BuildContext context, int index);
class TimeLineWidget extends StatelessWidget {
const TimeLineWidget(
{Key? key,
required this.iconItem,
required this.lineItem,
required this.itemBuilder,
required this.itemCount,
this.lineItemSpace})
: super(key: key);
final IconItem iconItem;
final LineItem lineItem;
final IndexedTimeItemBuilder itemBuilder;
final double? lineItemSpace;
final int itemCount;
@override
Widget build(BuildContext context) {
return ListView.builder(
shrinkWrap: true,
itemBuilder: (context, index) {
InfoItem timeItem = itemBuilder(context, index);
return Stack(
children: [
if (index != itemCount - 1)
Positioned(
child: Container(
width: lineItem.width,
color:
timeItem.isActive ? lineItem.activeColor : lineItem.color,
),
left: (iconItem.width-lineItem.width )/ 2,
bottom: 0,
top: 0,
),
Positioned(
child:
timeItem.isActive ? iconItem.activeWidget : iconItem.widget,
top: 0,
),
Padding(
padding: EdgeInsets.only(
left: lineItemSpace! + iconItem.width, bottom: 5),
child:
timeItem.isActive ? timeItem.activeWidget : timeItem.widget,
),
],
);
},
itemCount: itemCount,
);
}
}
class LineItem {
final Color color;
final Color activeColor;
final double width;
LineItem(
{required this.color, required this.width, required this.activeColor});
}
class IconItem {
final double width;
final Widget widget;
final Widget activeWidget;
IconItem(
{required this.width, required this.widget, required this.activeWidget});
}
class InfoItem {
final bool isActive;
final Widget widget;
late final Widget? activeWidget;
InfoItem({required this.isActive, required this.widget, this.activeWidget});
}
调用示范:
import 'package:flitter_okgo/time_line.dart';
import 'package:flutter/material.dart';
void main() => runApp(StartPage());
class StartPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: TestPage(),
);
}
}
class TestPage extends StatefulWidget {
@override
_TestPageState createState() => _TestPageState();
}
class _TestPageState extends State
with SingleTickerProviderStateMixin {
@override
void initState() {
super.initState();
}
final int len = 10;
final double iconWidth = 10;
final double lineItemSpace = 20;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('时间线'),
),
body: Padding(
padding: EdgeInsets.all(15),
child: TimeLineWidget(
itemCount: len,
lineItem: LineItem(
width: 2,
color: Colors.grey,
activeColor: Colors.red,
),
lineItemSpace: lineItemSpace,
iconItem: IconItem(
widget: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Container(
color: Colors.grey,
width: iconWidth,
height: iconWidth,
),
),
activeWidget: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Container(
color: Colors.red,
width: iconWidth,
height: iconWidth,
),
),
width: iconWidth,
),
itemBuilder: (context, index) {
return InfoItem(
isActive: index != 0,
widget: Container(
height: (index + 1) * 30,
child: Text(
'第$index个',
style: TextStyle(color: Colors.grey),
),
),
activeWidget: Container(
height: (index + 1) * 30,
child: Text('第$index个'),
),
);
},
),
),
);
}
}