I'm trying to implement a chat screen in my app and I want to display the dates before the conversation ( today, yesterday in most chatting apps ).
To display messages I use the itemBuilder
and to show these dates I used seperatorBuilder
of Listview.seperated
.
The problem is that the date widget appears after the message, which was supposed to indicate the date.
(here, the 'yesterday' widget was supposed to come above the 'hey' message). (the seperatorBuilder
builds after itemBuilder
)
I thought to switch the codes of seperatorBuilder
and itemBuilder
(build the chat bubble in seperatorbuilder and dater widget in itemBuilder) to get the build order I want but I doubt its performance.
CODE:
ListView.separated(
separatorBuilder: (context, index) {
if (index == 0 ||
compareDate(
currentSnap: snapshot.data!.docs[index] //snapshot from StreamBuilder
.data()['serverTimeStamp'],
previousSnap: snapshot.data!.docs[index - 1]
.data()['serverTimeStamp'])) // some checks before displaying
{return chatDater(); // the Widget that displays date container
} else {
return SizedBox(
width: 0,
height: 0,
);
}
},
controller: _controller1,
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index)
return MessageBubble(
timestamp:
snapshot.data!.docs[index].data()['serverTimeStamp'],
message: snapshot.data!.docs[index].data()['message'],
IsYou: snapshot.data!.docs[index].data()['sender'] ==
widget.usernameOfFriend
? false
: true,
);
},
)
the compareDate
method:
checks if two consecutive messages have different dates, if yes then returns true (so that we can display the dater widget)
bool compareDate(
{required Timestamp currentSnap, required Timestamp previousSnap}) {
var currentDate = currentSnap.toDate();
var previousDate = previousSnap.toDate();
if (currentDate.year != previousDate.year) return true;
if (currentDate.month != previousDate.month) return true;
if (currentDate.day != previousDate.day) return true;
return false;
}
CodePudding user response:
Add timestamp also in itemBuilder
when needed. Here is the simplified version:
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: messages.length,
itemBuilder: (BuildContext context, int index) {
final previous = index > 0 ? messages[index - 1] : null;
final current = messages[index];
final date = showDate(current, previous);
return Column(
children: [
if (date != null)
Text(date.toString()),
Text(current.text),
]
);
},
);
}
String? showDate(Message current, Message? previous) {
// TODO control when date is shown
if (previous == null) {
return current.date.toString();
} else {
return null;
}
}