ListView.builder 仅在热重载 flutter 应用程序后加载
ListView.builder only loads after hot-reloading flutter app
当用户登录到我的 flutter 应用程序时,他们必须登录,然后他们会被带到一个带有帖子提要的屏幕。我使用 ListView.builder
从我的数据库中获取帖子列表并创建帖子提要。我的问题是,当提要屏幕最初启动时,ListView
没有加载。一旦我热重新加载应用程序,列表就会加载。我想我的代码中有一个非常明显的小错误,但我就是找不到它。我会将提要屏幕中的所有代码放在下面,请看一下,如果您发现错误,请告诉我。
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
static const String id = "home_screen";
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
// List allposts = [(post: Post, owner: String)];
Color _likeButtonColor = Colors.black;
Widget _buildPost(String username, String imageUrl, String caption) {
return Container(
color: Colors.white,
child: Column(
children: [
Container(
height: 50,
color: Colors.deepOrangeAccent[100],
child: Row(
children: [
SizedBox(width: 5),
CircleAvatar(),
SizedBox(width: 5),
Text(username, style: TextStyle(fontSize: 15)),
SizedBox(width: 225),
Icon(Icons.more_horiz)
],
),
),
Stack(
children: [
Image.asset("images/post_background.jpg"),
Padding(
padding: const EdgeInsets.all(20.0),
child: ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: Image.network(imageUrl, fit: BoxFit.cover)),
),
],
),
Container(
height: 100,
child: Column(
children: [
const SizedBox(height: 5),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconButton(
onPressed: () {
setState(() {
HapticFeedback.lightImpact();
});
},
icon: Icon(Icons.thumb_up_alt_outlined, size: 30)),
Text("l", style: TextStyle(fontSize: 30)),
Icon(Icons.ios_share, size: 30)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(caption, style: const TextStyle(fontSize: 15))
],
)
],
),
)
],
),
);
}
List<Post> listPosts = [];
fetchPosts() async {
final userRef = FirebaseFirestore.instance.collection('users');
final QuerySnapshot result = await userRef.get();
result.docs.forEach((res) async {
print(res.id);
QuerySnapshot posts = await userRef.doc(res.id).collection("posts").get();
posts.docs.forEach((res) {
listPosts.add(Post.fromJson(res.data() as Map<String, dynamic>));
});
});
}
@override
void initState() {
fetchPosts();
print(listPosts);
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: listPosts.length,
itemBuilder: (BuildContext context, int index) {
// We retrieve the post at index « index »
final post = listPosts[index];
// Replace with your actual implementation of _buildPost
return _buildPost(post.id, post.postUrlString, post.caption);
}),
);
}
}
原因是您需要重建屏幕以在执行异步操作后显示反映的更改(使用 setState 重建 UI)。其次,.forEach 循环不是为承载异步内容而构建的,而且效率低于普通的 for 循环,因此最好更改它。
fetchPosts() async {
final userRef = FirebaseFirestore.instance.collection('users');
final QuerySnapshot result = await userRef.get();
for(var res in result.docs)async{
print(res.id);
QuerySnapshot posts = await userRef.doc(res.id).collection("posts").get();
posts.docs.forEach((res) {
listPosts.add(Post.fromJson(res.data() as Map<String, dynamic>));
});
}
setState((){});//call it after end of your function
}
Ps:- 您可以使用名为 loading 的变量来显示进度指示器,并在 setState 中获取数据后将其设置为 false。
当用户登录到我的 flutter 应用程序时,他们必须登录,然后他们会被带到一个带有帖子提要的屏幕。我使用 ListView.builder
从我的数据库中获取帖子列表并创建帖子提要。我的问题是,当提要屏幕最初启动时,ListView
没有加载。一旦我热重新加载应用程序,列表就会加载。我想我的代码中有一个非常明显的小错误,但我就是找不到它。我会将提要屏幕中的所有代码放在下面,请看一下,如果您发现错误,请告诉我。
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
static const String id = "home_screen";
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
// List allposts = [(post: Post, owner: String)];
Color _likeButtonColor = Colors.black;
Widget _buildPost(String username, String imageUrl, String caption) {
return Container(
color: Colors.white,
child: Column(
children: [
Container(
height: 50,
color: Colors.deepOrangeAccent[100],
child: Row(
children: [
SizedBox(width: 5),
CircleAvatar(),
SizedBox(width: 5),
Text(username, style: TextStyle(fontSize: 15)),
SizedBox(width: 225),
Icon(Icons.more_horiz)
],
),
),
Stack(
children: [
Image.asset("images/post_background.jpg"),
Padding(
padding: const EdgeInsets.all(20.0),
child: ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: Image.network(imageUrl, fit: BoxFit.cover)),
),
],
),
Container(
height: 100,
child: Column(
children: [
const SizedBox(height: 5),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconButton(
onPressed: () {
setState(() {
HapticFeedback.lightImpact();
});
},
icon: Icon(Icons.thumb_up_alt_outlined, size: 30)),
Text("l", style: TextStyle(fontSize: 30)),
Icon(Icons.ios_share, size: 30)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(caption, style: const TextStyle(fontSize: 15))
],
)
],
),
)
],
),
);
}
List<Post> listPosts = [];
fetchPosts() async {
final userRef = FirebaseFirestore.instance.collection('users');
final QuerySnapshot result = await userRef.get();
result.docs.forEach((res) async {
print(res.id);
QuerySnapshot posts = await userRef.doc(res.id).collection("posts").get();
posts.docs.forEach((res) {
listPosts.add(Post.fromJson(res.data() as Map<String, dynamic>));
});
});
}
@override
void initState() {
fetchPosts();
print(listPosts);
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: listPosts.length,
itemBuilder: (BuildContext context, int index) {
// We retrieve the post at index « index »
final post = listPosts[index];
// Replace with your actual implementation of _buildPost
return _buildPost(post.id, post.postUrlString, post.caption);
}),
);
}
}
原因是您需要重建屏幕以在执行异步操作后显示反映的更改(使用 setState 重建 UI)。其次,.forEach 循环不是为承载异步内容而构建的,而且效率低于普通的 for 循环,因此最好更改它。
fetchPosts() async {
final userRef = FirebaseFirestore.instance.collection('users');
final QuerySnapshot result = await userRef.get();
for(var res in result.docs)async{
print(res.id);
QuerySnapshot posts = await userRef.doc(res.id).collection("posts").get();
posts.docs.forEach((res) {
listPosts.add(Post.fromJson(res.data() as Map<String, dynamic>));
});
}
setState((){});//call it after end of your function
}
Ps:- 您可以使用名为 loading 的变量来显示进度指示器,并在 setState 中获取数据后将其设置为 false。