I’d like to go to the bottom in the list builder, on the last message and auto scroll to the bottom. I would like the newer messages to the bottom like WhatsApp or other chat.
I’m tested a lot of solution without success. Please let me know how can I solve this issue.
Thanks you.
here the code :
Future<ResponseGetDiscussionMessage> getDiscussionMessage(
{required idDiscussion}) async {
ResponseGetDiscussionMessage? responseGetDiscussionMessage;
Map<String, dynamic> customBody = {
"action": 28,
"idDiscussion": idDiscussion,
"offset": 0,
"limit": null
};
var res = await ApiCallPost().apiCall(customBody);
return ResponseGetDiscussionMessage.fromJson(res);
}
(...)
final ScrollController _scrollController = ScrollController();
@override
void initState() {
super.initState();
futureCreateDiscussion =
createDiscussion(name: "", idUser: widget.varToPage);
// Scroll to bottom after the first frame is rendered
WidgetsBinding.instance.addPostFrameCallback((_) => scrollToBottom());
}
// Method to scroll to the bottom
void scrollToBottom() {
if (_scrollController.hasClients) {
_scrollController.animateTo(
_scrollController.position.maxScrollExtent,
duration: const Duration(milliseconds: 300),
curve: Curves.easeOut,
);
}
}
(...)
@override
void dispose() {
// TODO: implement dispose
_textNotifier.dispose();
_controllerEnvoieMessage.dispose();
_scrollController.dispose();
super.dispose();
}
SizedBox(
child: Column(
children: [
FutureBuilder<ResponseCreateDiscussion>(
future: futureCreateDiscussion,
builder: (BuildContext context, snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Center(
child: Text(
'Erreur : ${snapshot.error}'));
} else {
discussionDetail['idDiscussion'] =
snapshot.data!.result.id;
futureGetDiscussionMessage =
getDiscussionMessage(
idDiscussion: discussionDetail[
'idDiscussion']);
return Container(
child: Column(
children: [
Container(
child: FutureBuilder<
ResponseGetDiscussionMessage>(
future:
futureGetDiscussionMessage,
builder:
(BuildContext context,
snapshot) {
if (snapshot
.connectionState ==
ConnectionState
.waiting) {
return const Center(
child:
CircularProgressIndicator());
} else if (snapshot
.hasError) {
return Center(
child: Text(
'Erreur : ${snapshot.error}'));
} else {
return ListView
.builder(
// controller: _scrollController,
controller:
_scrollController,
// reverse: true,
itemCount: snapshot
.data
?.result
.length ??
0,
scrollDirection:
Axis
.vertical,
shrinkWrap:
true,
physics:
const NeverScrollableScrollPhysics(),
itemBuilder:
(BuildContext
contex,
int index) {
String? lastUser = index ==
0
? null
: snapshot
.data!
.result[index -
1]
.firstname;
bool isFirstMessageForUser = lastUser !=
snapshot
.data!
.result[index]
.firstname;
return Align(
alignment: snapshot.data!.result[index].isOwner ==
false
? Alignment.topLeft
: Alignment.topRight,
child: Container(
margin: const EdgeInsets.only(right: 15, left: 15),
constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width * 0.8,
),
child: IntrinsicWidth(
child: Card(
color: ColorsDiolos.vertClair,
elevation: 0,
child: Container(
padding: const EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5),
alignment: snapshot.data!.result[index].isOwner == false ? Alignment.topLeft : Alignment.topRight,
child: Column(crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [
Text("${snapshot.data!.result[index].date}"),
if (isFirstMessageForUser)
Row(
children: [
CircleAvatar(
radius: 20,
backgroundImage: NetworkImage("$urlSite/file/user-profile/${snapshot.data!.result[index].image}"),
),
Text(
"${snapshot.data!.result[index].firstname}",
style: const TextStyle(
color: ColorsDiolos.violetClair,
fontWeight: FontWeight.bold,
),
),
],
),
Align(
alignment: snapshot.data!.result[index].isOwner == false ? Alignment.topLeft : Alignment.topRight,
child: Text(
"${snapshot.data!.result[index].data!.text}",
style: TextStyle(color: ColorsDiolos.violetFonce, fontWeight: FontWeight.bold, fontSize: (snapshot.data!.result[index].data!.text!.length > 2) || (isEmoji("${snapshot.data!.result[index].data!.text}") == false) ? 17 : 60),
))
]))))));
});
}
}))
],
),
);
}
}),
],
),
),
(...)
I would like to read the message with the last to the top and last to the bottom.
2
Answers
Solved. I put the controller on SingleChildScrollView() and not with ListView.builder
Thank you,
To implement
auto-scrolling
in aListView
like a chat application, where new messages appear at the bottom, here are a few steps that should help achieve the desired behavior.Solution Steps
Complete Code Solution
Here’s an updated version of your code that includes these steps. It uses WidgetsBinding.instance.addPostFrameCallback to scroll after the UI frame is rendered, ensuring smooth scrolling to the bottom whenever a new message arrives.
Explanation of Changes:
With this setup, each time a new message is added, the ListView will scroll to the latest message at the bottom. This simulates the chat behavior you see in messaging apps like WhatsApp.