I am trying to create a comment page. The list of comments are listed using ListView.builder. And when the user enter a comment, it will rebuild the list again to include the newly added comment. But somehow the list is not rebuild and i'm getting this message in terminal:
Changing the content within the the composing region may cause the input method to behave strangely, and is therefore discouraged. See https://github.com/flut ter/flutter/issues/78827 for more details
The newly added comment only shows when i close the comment page and reopen it again. Please help me, as i am not sure what is the issue and how to fix it.
Comment Page:
import 'package:flutter/material.dart';
import '../model/model_comment.dart';
class CommentsPage extends StatefulWidget {
@override
_CommentsPageState createState() => _CommentsPageState();
}
class _CommentsPageState extends State<CommentsPage> {
ValueNotifier<int> _counter = ValueNotifier<int>(0);
TextEditingController _controllerComment = TextEditingController();
bool _hasComment = false;
@override
void dispose() {
_controllerComment.dispose();
super.dispose();
}
_commentOnSend() {
setState(() {
var value = CommentModel(
avatarUrl: "https://randomuser.me/api/portraits/women/34.jpg",
name: "Laurent Oslo",
dateTime: "30 Dec 20 08:00",
comment: _controllerComment.text,
);
CommentModel.dummyData.insert(0, value);
});
_controllerComment.clear();
FocusScope.of(context).unfocus();
}
Widget _listView = ListView.builder(
itemCount: CommentModel.dummyData.length,
itemBuilder: (context, index) {
CommentModel _model = CommentModel.dummyData[index];
return Column(
children: <Widget>[
Divider(
height: 12.0,
),
Container(
padding: EdgeInsets.fromLTRB(3.0, 3.0, 3.0, 3.0),
child: ListTile(
leading: CircleAvatar(
radius: 24.0,
backgroundImage: NetworkImage(_model.avatarUrl),
),
title: Text(_model.name),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(_model.comment),
Text(_model.dateTime),
],
),
),
),
],
);
},
);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Comments"),
titleSpacing: 40.0,
),
body: Container(
child: Column(
children: [
Expanded(child: _listView),
Divider(
height: 1.0,
),
ListTile(
leading: Container(
height: 40.0,
width: 40.0,
decoration: BoxDecoration(
color: Colors.deepPurple,
borderRadius: BorderRadius.all(Radius.circular(50.0))),
child: CircleAvatar(
radius: 50.0,
backgroundImage: NetworkImage(
"https://randomuser.me/api/portraits/men/83.jpg")),
),
title: TextField(
decoration: (InputDecoration(
hintText: "Add Comment"
)),
minLines: 1,
maxLines: 5,
controller: _controllerComment,
onChanged: (val) {
setState(() {
_counter.value += 1;
if (val.isNotEmpty) {
_hasComment = true;
} else {
_hasComment = false;
}
});
}),
trailing: ValueListenableBuilder(
valueListenable: _counter,
builder: (BuildContext context, int value, Widget? child) {
return IconButton(
onPressed: _hasComment
? () {
_commentOnSend();
}
: null,
icon: Icon(Icons.send_sharp,
color: _hasComment ? Colors.deepPurple : null),
);
},
),
),
],
),
),
);
}
}
Comment Model Class:
class CommentModel {
final String avatarUrl;
final String name;
final String dateTime;
final String comment;
CommentModel(
{required this.avatarUrl,
required this.name,
required this.dateTime,
required this.comment});
static List<CommentModel> dummyData = [
CommentModel(
avatarUrl: "https://randomuser.me/api/portraits/women/34.jpg",
name: "Laurent Oslo",
dateTime: "30 Dec 20 08:00",
comment:
"There is a reason why I implemented it like this. In a comment section, the same comment widget can appear multiple times. So, the keys assigned to each widget needs to be different. Otherwise I won’t be able to refer to a specific widget later on",
),
CommentModel(
avatarUrl: "https://randomuser.me/api/portraits/women/49.jpg",
name: "Tracy Wilbur",
dateTime: "01 Oct 20 17:00",
comment: "First Comment!",
),
CommentModel(
avatarUrl: "https://randomuser.me/api/portraits/women/23.jpg",
name: "Michael Scott",
dateTime: "30 Sept 20 06:00",
comment:
"The idea is simple. Use the prefix with something else to make the key unique. In this case, I’ve used the index value to make them unique. I used the keys in line 25, 51, 56, and 60. See how I’ve done it in these lines.",
),
CommentModel(
avatarUrl: "https://randomuser.me/api/portraits/men/45.jpg",
name: "Williams John",
dateTime: "17 Sept 20 02:00",
comment: "Join!",
),
CommentModel(
avatarUrl: "https://randomuser.me/api/portraits/women/77.jpg",
name: "Claire Rach",
dateTime: "15 Aug 20 19:00",
comment:
"I want the comment section to be hidden away. A user can view comments by tapping to expand a widget. Meaning, the comment section should be collapsible. It will toggle between expanded and collapsed mode when being tapped.",
),
CommentModel(
avatarUrl: "https://randomuser.me/api/portraits/men/81.jpg",
name: "Joe Panama",
dateTime: "05 Jul 20 03:00",
comment:
"A comment will have 3 data values which are commenting user details, time of comment posting and the actual text of the comment. I’ve created a “CommentModel” class to create this model.",
),
CommentModel(
avatarUrl: "https://randomuser.me/api/portraits/men/83.jpg",
name: "Mark Hamill",
dateTime: "09 Jun 20 15:00",
comment:
"Because comments are part of a post, “PostModel” needs to have a list of comment data. So I’ve modified “PostModel” to have a list of “CommentModel” objects. Refer to the code changes to see what I’ve done.",
),
CommentModel(
avatarUrl: "https://randomuser.me/api/portraits/men/85.jpg",
name: "Williams Dafoe",
dateTime: "25 May 20 20:00",
comment:
"Notice lines 18 to 29. I’ve used the “ExpansionTile” widget to create a collapsible list of comments. Each comment is a “_SingleComment” widget implemented in lines 34 to 67.",
),
CommentModel(
avatarUrl: "https://randomuser.me/api/portraits/men/98.jpg",
name: "Phillips Mach",
dateTime: "01 Apr 20 17:00",
comment:
"New to app development and flutter in general(high schooler). Can I use this template? Do I have to give credit or can I just use it? At the very least, can I see the source code so I can learn from it?",
),
CommentModel(
avatarUrl: "https://randomuser.me/api/portraits/men/12.jpg",
name: "Joe Snowden",
dateTime: "04 Mar 20 16:00",
comment: "PM ME!",
),
];
}
Solution 1: user15873802
This is because you are putting your Listview.builder
in a state variable which is expected behavior since state variables do not get reinitialized in rebuilds.
If you want to refactor you can create a new function to return it:
ListView getList(){
return ListView.builder(
itemCount: CommentModel.dummyData.length,
itemBuilder: (context, index) {
CommentModel _model = CommentModel.dummyData[index];
return Column(
children: <Widget>[
Divider(
height: 12.0,
),
Container(
padding: EdgeInsets.fromLTRB(3.0, 3.0, 3.0, 3.0),
child: ListTile(
leading: CircleAvatar(
radius: 24.0,
backgroundImage: NetworkImage(_model.avatarUrl),
),
title: Text(_model.name),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(_model.comment),
Text(_model.dateTime),
],
),
),
),
],
);
},
);
}