Implementing a timeline-based Dismissable ListTile Widget
I've added circles to each ListTile as you wanted
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:intl/intl.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
body: SafeArea(
child: MyHomePage(),
),
),
);
}
}
const kWhite = Colors.white;
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final _items = <Order>[
Order(
id: 'id-1',
date: DateTime.now(),
number: 12,
intemNo: 20,
orderTotal: 20000,
status: OrderStatus.inProgress,
),
Order(
id: 'id-2',
date: DateTime.now().subtract(Duration(days: 10)),
number: 10,
intemNo: 2,
orderTotal: 5000,
status: OrderStatus.delivered,
),
];
DateFormat dateFormate = DateFormat.yMd();
@override
Widget build(BuildContext context) {
return ListView.separated(
separatorBuilder: (context, index) => Divider(
indent: 10.0,
endIndent: 10.0,
color: Colors.black,
),
itemCount: _items.length,
itemBuilder: (context, index) {
var item = _items[index];
return Dismissible(
direction: DismissDirection.startToEnd,
key: Key(item.id),
onDismissed: (dir) {
setState(() => _items.removeAt(index));
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text(dir == DismissDirection.startToEnd
? '$item removed.'
: '$item liked.'),
action: SnackBarAction(
label: 'UNDO',
onPressed: () {
setState(() => _items.insert(index, item));
},
),
),
);
},
background: Container(
color: Colors.red,
padding: EdgeInsets.all(10),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FaIcon(
FontAwesomeIcons.times,
color: kWhite,
),
SizedBox(
height: 10,
),
Text(
'Cancel \n Order',
style: TextStyle(color: kWhite),
)
],
),
alignment: Alignment.centerLeft,
),
child: ListTile(
title: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
'Order No: ${item.number}',
),
Text('items no: ${item.intemNo}'),
],
),
SizedBox(
height: 20,
),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
'Order Total: ${item.orderTotal}',
),
Text(dateFormate.format(item.date)),
],
),
SizedBox(
height: 20,
),
StatusBar(
status: item.status,
)
],
),
),
),
);
},
);
}
}
class StatusBar extends StatelessWidget {
const StatusBar({Key key, this.status}) : super(key: key);
final OrderStatus status;
final List<String> titles = const [
'waiting',
'in progress',
'delivering',
'delivered'
];
@override
Widget build(BuildContext context) {
var checkedCount = _getCheckedCount(status);
var elements = List<bool>.generate(4, (i) => i < checkedCount);
return Column(
children: <Widget>[
Stack(
children: [
Positioned(
top: 25,
left: 10,
right: 10,
child: Container(
height: 4,
color: Colors.black38,
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: elements
.asMap()
.map((index, isChecked) => MapEntry(
index,
Column(
children: <Widget>[
Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.deepOrange,
),
alignment: Alignment.center,
width: 50,
height: 50,
child: isChecked
? FaIcon(
FontAwesomeIcons.check,
color: kWhite,
)
: null,
),
Text(titles[index])
],
),
))
.values
.toList(),
),
],
),
],
);
}
_getCheckedCount(OrderStatus status) {
switch (status) {
case OrderStatus.waiting:
return 1;
case OrderStatus.inProgress:
return 2;
case OrderStatus.deliviring:
return 3;
case OrderStatus.delivered:
return 4;
}
}
}
class Order {
final String id;
final int number;
final int intemNo;
final int orderTotal;
final DateTime date;
final OrderStatus status;
Order({
@required this.id,
@required this.number,
@required this.intemNo,
@required this.orderTotal,
@required this.date,
@required this.status,
});
}
enum OrderStatus { waiting, inProgress, deliviring, delivered }
Waleed Alrashed
Mobile Apps Developer using Flutter Framework
Updated on December 21, 2022Comments
-
Waleed Alrashed over 1 year
Note: Before Getting into the question,I would like to get everyone into the scope of the problem, Here's my ultimate goal:
- Developing a reactive
ListTile
Widget that responds to the events coming from the backend by changing it's current state.
I'll leave that for another question. for now, Here's my Goal from this question
Goal: Designing a
statefull
widget that has multiple custom components like a Circle and timeline-related widgets and placing it inside aDismissable Listile
alongside other components as shown in the following screenshotI have so far implemented the
ListView
Screen with theDismissable ListTile
that contains theText
widgets that are shown in the previous design.Here's the code for what I have currently:
ListView.builder( itemCount: _items.length, itemBuilder: (context, index) { final String item = _items[index]; return Dismissible( direction: DismissDirection.startToEnd, key: Key(item), onDismissed: (DismissDirection dir) { setState(() => this._items.removeAt(index)); Scaffold.of(context).showSnackBar( SnackBar( content: Text(dir == DismissDirection.startToEnd ? '$item removed.' : '$item liked.'), action: SnackBarAction( label: 'UNDO', onPressed: () { setState(() => this._items.insert(index, item)); }, ), ), ); }, background: Container( color: Colors.red, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ FaIcon( FontAwesomeIcons.times, color: kWhite, ), SizedBox( height: 10, ), Text( 'Cancel Order', style: TextStyle(color: kWhite), ) ], ), alignment: Alignment.centerLeft, ), child: ListTile( //CustomeTimeLineWidget goes here innstead of the container title: Container( child: Column( children: <Widget>[ Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ Text( 'Order No: 002345', ), Text('items no: 12'), ], ), SizedBox( height: 20, ), Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ Text( 'Order Total: 20000', ), Text('17/04/2020'), ], ), ], ), ), ), ); }, ),
And Here's the resulting Design from that code
Tried-Solutions: I have considered using the Timeline Package, but it shows the vertical timeline instead of Horizontal one.
Problem: I need to implement the timeline (The Circles in each
ListTile
) - Developing a reactive