Flutter无限滚动GridView项重复问题求助
GridView所有项内容重复的问题解决
核心问题分析
- 单一随机值导致全局重复:主页面
FutureBuilder中仅生成一次random_pet,所有Random_Image_Card组件都接收同一个参数,自然显示完全相同的内容。 - 无限滚动逻辑失效:当前仅在滚动到底部时递增
pageNumber并调用setState,但API.get_pets未使用pageNumber参数,也未合并新请求数据,无法实现真正的无限加载。 - FutureBuilder重复请求隐患:直接将
API.get_pets(randomly_select_URL())作为future参数,页面每次重建都会触发新的API请求,造成资源浪费。
修复方案
1. 主页面代码修正
维护已加载数据列表实现分页累加,为每个项生成独立随机索引,修正无限滚动逻辑:
import 'package:flutter/material.dart'; import 'package:pet_store/utils/utils.dart'; import 'package:pet_store/widgets/random_pet_image.dart'; import 'webservice/API.dart'; import 'main.dart'; class Infinite_Scroll_Game extends StatefulWidget { const Infinite_Scroll_Game({Key? key}) : super(key: key); @override State<Infinite_Scroll_Game> createState() => _Infinite_Scroll_GameState(); } class _Infinite_Scroll_GameState extends State<Infinite_Scroll_Game> { ScrollController _scrollController = ScrollController(); int pageNumber = 1; List<dynamic> allPetData = []; bool isLoading = false; @override void initState() { super.initState(); _fetchPetData(); _scrollController.addListener(() { if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent && !isLoading) { pageNumber++; _fetchPetData(); } }); } void _fetchPetData() async { setState(() => isLoading = true); try { final newData = await API.get_pets(randomly_select_URL()); setState(() { allPetData.addAll(newData); isLoading = false; }); } catch (e) { setState(() => isLoading = false); // 按需添加错误提示逻辑 } } @override void dispose() { _scrollController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( resizeToAvoidBottomInset: false, appBar: AppBar( backgroundColor: Colors.indigo, title: const Text('Infinite Scroll Game'), leading: GestureDetector( child: const Icon(Icons.arrow_back_ios, color: Colors.white), onTap: () { Navigator.pushAndRemoveUntil( context, MaterialPageRoute(builder: (context) => const HomePage()), (route) => false, ); }, ), ), body: Padding( padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 12.0), child: allPetData.isEmpty ? const Center(child: CircularProgressIndicator()) : Stack( children: [ GridView.builder( controller: _scrollController, gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, crossAxisSpacing: 12.0, mainAxisSpacing: 12.0, ), itemCount: allPetData.length + (isLoading ? 1 : 0), itemBuilder: (context, index) { if (index == allPetData.length) { return const Center(child: CircularProgressIndicator()); } // 为每个项生成独立随机宠物索引 final randomPetIndex = random.nextInt(allPetData.length); return Random_Image_Card(petData: allPetData[randomPetIndex]); }, ), ], ), ), ); } }
2. 卡片组件代码修正
直接接收单个宠物数据,组件内部独立处理图片随机选择:
import 'package:flutter/material.dart'; import 'package:pet_store/utils/utils.dart'; class Random_Image_Card extends StatefulWidget { final dynamic petData; const Random_Image_Card({required this.petData, Key? key}) : super(key: key); @override State<Random_Image_Card> createState() => _Random_Image_CardState(); } class _Random_Image_CardState extends State<Random_Image_Card> { List<dynamic> photoURL = []; int? selectedImage; @override void initState() { super.initState(); photoURL = widget.petData['photoUrls'] ?? []; if (photoURL.isNotEmpty) { selectedImage = random.nextInt(photoURL.length); } } @override Widget build(BuildContext context) { return SizedBox( height: 180, width: 180, child: Card( child: Container( decoration: photoURL.isNotEmpty && selectedImage != null ? BoxDecoration( image: DecorationImage( alignment: Alignment.center, image: image(photoURL[selectedImage!]).image, fit: BoxFit.scaleDown, ), ) : const BoxDecoration( image: DecorationImage( alignment: Alignment.center, image: NetworkImage("https://cdn-cziplee-estore.azureedge.net//cache/no_image_uploaded-253x190.png"), fit: BoxFit.scaleDown, ), ), ), ), ); } }
关键修改说明
- 主页面维护
allPetData列表,滚动到底部时加载新数据并累加,实现真正的无限滚动 - 每个GridView项在
itemBuilder中生成独立随机宠物索引,确保卡片内容不重复 - 卡片组件直接接收单条宠物数据,独立处理图片随机选择,摆脱对外部单一随机值的依赖
- 增加加载状态管理,避免重复发起API请求
内容的提问来源于stack exchange,提问作者Tindona
相关产品推荐
相关产品推荐

