đź”— Github
Introduction
In today’s digital age, interaction and engagement are at the heart of any successful mobile application. Whether you’re developing a social media platform, a blog reader, or an e-commerce app, providing users with a seamless and visually appealing comment section is a crucial element.
Flutter, with its rich set of widgets and powerful customization options, is the perfect tool to elevate your app’s user experience by creating an exceptional comment section. In this blog post, we’ll embark on a journey into the world of Flutter, where we’ll explore the art of designing a comment section UI that not only looks fantastic but also enhances user interaction.
By the end of this guide, you’ll be equipped with the knowledge and skills to implement a captivating comment section in your Flutter mobile app. So, whether you’re a seasoned Flutter developer or just starting your Flutter adventure, let’s dive in and transform your app’s comment section into a vibrant and engaging community hub!
Prerequisite
I’m using flutter_svg package for the profile picture on the comments. The profile pictures will be from DiceBear.
flutter_svg: ^2.0.6
Code Snippet
To implement a robust comment system in Flutter, we often need a well-structured data model to manage comment data effectively. In this blog post, we’ll explore two essential classes, Comments
and Reply
, designed to do just that.
The Comments
Class
class Comments {
final String userName;
final String imageURL;
final String content;
final String type;
final String id;
final List<Reply> replies;
Comments(
this.replies, {
required this.userName,
required this.imageURL,
required this.content,
required this.type,
required this.id,
});
}
The Comments
class represents top-level comments. It includes properties such as userName
(the commenter’s name), imageURL
(the commenter’s avatar URL), content
(the comment text or content URL), type
(indicating whether it’s text or a GIF), and more. Crucially, it has a List
of Reply
objects, enabling nested comments.
The Reply
Class
class Reply {
final String userName;
final String imageURL;
final String content;
final String type;
final String id;
Reply({
required this.userName,
required this.imageURL,
required this.content,
required this.type,
required this.id,
});
}
The Reply
class represents individual replies to comments, and it shares similar properties with Comments
. This structured approach allows for consistency and easy management of comment data, including usernames, content and more.
The ParentComment
Widget
class ParentComment extends StatelessWidget {
final Comment comment;
ParentComment({required this.comment});
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
flex: 1,
child: CircleAvatar(
child: SvgPicture.network(
comment.imageURL,
),
),
),
Expanded(
flex: 8,
child: ListTile(
trailing: IconButton(
onPressed: () {}, icon: Icon(Icons.favorite_border_rounded)),
dense: true,
title: Text(
comment.userName,
style: TextStyle(fontWeight: FontWeight.bold),
),
subtitle: comment.type == "text"
? Text(comment.content)
: ClipRRect(
borderRadius: BorderRadius.circular(12),
child: Image.network(comment.content),
),
),
),
],
);
}
}
The ParentComment
widget is designed to display top-level comments. It takes a Comment
object as a parameter and constructs a visual representation of that comment. Key features of this widget include:
- Displaying the commenter’s avatar using a
CircleAvatar
. - Showing the username and content of the comment.
- Providing a like button (currently non-functional).
The ReplyComment
Widget
class ReplyComment extends StatelessWidget {
final Reply reply;
ReplyComment({required this.reply});
@override
Widget build(BuildContext context) {
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
flex: 1,
child: CircleAvatar(
child: SvgPicture.network(
reply.imageURL,
),
),
),
Expanded(
flex: 8,
child: ListTile(
trailing: IconButton(
onPressed: () {},
icon: Icon(Icons.favorite_border_rounded)),
dense: true,
title: Text(
reply.userName,
style: TextStyle(fontWeight: FontWeight.bold),
),
subtitle: reply.type == "text"
? Text(reply.content)
: ClipRRect(
borderRadius: BorderRadius.circular(12),
child: Image.network(reply.content),
),
),
),
],
),
],
);
}
}
The ReplyComment
widget is similar to ParentComment
but is designed for displaying replies to comments. It takes a Reply
object as a parameter and constructs a visual representation of that reply. Key features include:
- Displaying the replier’s avatar.
- Showing the username and content of the reply.
- Providing a like button (also currently non-functional).
The CommentItem
Class
class CommentItem extends StatefulWidget {
final Comment comment;
const CommentItem({Key? key, required this.comment});
@override
State<CommentItem> createState() => _CommentItemState();
}
class _CommentItemState extends State<CommentItem> {
bool showReply = false;
@override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
ParentComment(comment: widget.comment),
if (!showReply)
if (widget.comment.replies.isNotEmpty)
TextButton(
onPressed: () {
setState(() {
showReply = true;
});
},
child: Text("Show ${widget.comment.replies.length} Replies"),
),
if (showReply)
...widget.comment.replies.map((reply) {
return Column(
children: [
Row(
children: [
Expanded(
child: Container(),
flex: 1,
),
Expanded(
child: ReplyComment(reply: reply),
flex: 8,
),
],
),
],
);
}).toList(),
Divider(),
],
),
);
}
}
How Nested Comments Work
- The
CommentItem
widget maintains a state (showReply
) to control the display of replies. - When a user taps the “Show X Replies” button, it toggles the
showReply
state, revealing the replies. - Replies are iterated through and displayed using the
ReplyComment
widget within aColumn
.
Example Data
Comment(
userName: "Jhanarthananraja",
imageURL:
"https://api.dicebear.com/7.x/big-smile/svg?seed=Jhanarthananraja",
content:
"This is a test comments! This is a test comments! This is a test comments! This is a test comments!",
type: "text",
id: "msg-001",
replies: [
Reply(
userName: "John Doe",
imageURL:
"https://api.dicebear.com/7.x/big-smile/svg?seed=JohnDoe",
content: "https://media.giphy.com/media/TmOpUpxHEtW7ZtdvUc/giphy.gif",
type: "gif",
id: "msg-002",
),
Reply(
userName: "Mary Jane",
imageURL:
"https://api.dicebear.com/7.x/big-smile/svg?seed=MaryJane",
content:
"This is a test reply",
type: "text",
id: "msg-003",
),
],
),
Screenshot
Full Code
The full code is available on my GitHub