Home > Software engineering >  How to build seperatorBuilder before itemBuilder in listview.seperated
How to build seperatorBuilder before itemBuilder in listview.seperated

Time:01-16

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;
  } 
}
  • Related