Flutter中如何从ListView.builder外部删除列表项
Flutter:从ListView.builder外部删除列表项的方法
我需要从ListView.builder外部删除指定的列表项,已知目标项的名称和索引。尝试通过ListView.removeAt(itemIndex)实现,但该方法无效。
页面包含两个FloatingActionButton:fab1和fab2。点击fab2时会调用removeItem(itemName)函数从数据库删除数据(此功能正常),数据删除后需要同步从ListView中移除对应项,但我不知道如何引用ListView来完成此操作。请问这种情况下如何从ListView中删除项?
原完整代码
Future<List<PostListDetails>> postsFuture = getPosts(); bool showButton = false; String itemName =""; int itemIndex = 0; static Future<List<PostListDetails>> getPosts() async { SharedPreferences prefs = await SharedPreferences.getInstance(); final token = await prefs.getString('token'); final listID = await prefs.getString('listID'); final lista = await prefs.getString('lista'); Response response = await post(Uri.parse('someURL'), headers: <String, String>{ 'Accept': 'application/json', 'Authorization': 'Bearer $token', }, body: <String, String>{ 'listID': '$listID', }, ); if(response.statusCode != 200){ print('Błąd połączenia z bazą danych... status[${response.statusCode}]'); } final List body = json.decode(response.body); return body.map((e) => PostListDetails.fromJson(e)).toList(); } void removeItem(String nazwa) async { SharedPreferences prefs = await SharedPreferences.getInstance(); final token = await prefs.getString('token'); final listID = await prefs.getString('listID'); try{ Response response = await post(Uri.parse('SomeURL'), headers: <String, String>{ 'Accept': 'application/json', 'Authorization': 'Bearer $token', }, body: <String, String>{ 'listID': '$listID', 'nazwa': nazwa, }, ); if(response.statusCode == 200) { //ListView.removeAt(itemIndex); <--- 不知道该怎么写这部分代码 }else{ print('Błąd połączenia z bazą danych... status[${response.statusCode}]'); } }catch(e){ print(e.toString()); } } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.grey[100], floatingActionButton: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ FloatingActionButton.extended( heroTag: "fab1", onPressed: () { print('---> addList()'); // addList(); }, icon: const Icon(Icons.add_circle_outline), label: const Text('Dodaj'), ), if (showButton) FloatingActionButton.extended( heroTag: "fab2", onPressed: () { print('---> removing $itemName'); removeItem(itemName); // 此函数负责从数据库删除数据 setState(() => showButton = false); }, icon: const Icon(Icons.delete), label: const Text('Usuń'), ), ], ), appBar: AppBar( backgroundColor: Colors.grey[900], title: const Text('Lista zakupowa'), actions: [ IconButton( onPressed: signUserOut, icon: const Icon(Icons.logout), ), ], ), body: Center( child: FutureBuilder<List<PostListDetails>>( future: postsFuture, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const CircularProgressIndicator(); } else if (snapshot.hasData) { return buildPosts(snapshot.data!); } else { return const Text("Brak danych..."); } }, ), ), ); } @override Widget buildPosts(List<PostListDetails> posts) { return ListView.builder( itemCount: posts.length, itemBuilder: (context, index) { final post = posts[index]; int customCompare(PostListDetails a, PostListDetails b) { if (a.status != b.status) { return a.status!.toInt() - b.status!.toInt(); } final int categoryCompare = a.kategoria.toString().compareTo(b.kategoria.toString()); if (categoryCompare != 0) { return categoryCompare; } return a.nazwa.toString().compareTo(b.nazwa.toString()); } return GestureDetector( onLongPress: () { itemName = post.nazwa!; itemIndex = index; setState(() => showButton = true); }, child: Container( color: post.status! % 2 == 1 ? Colors.grey[100] : Colors.white, margin: const EdgeInsets.symmetric(vertical: 0.5, horizontal: 0), padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 15), height: 50, width: double.maxFinite, child: Row( children: [ Expanded( flex: 8, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( post.nazwa!, textAlign: TextAlign.left, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 15, color: Colors.black), ), Text( '${post.waga!.toString()} g.', textAlign: TextAlign.left, style: const TextStyle(fontWeight: FontWeight.normal, fontSize: 15, color: Colors.grey), ), ], ), ), Expanded( flex: 2, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Expanded( flex: 0, child: Row(), ), Expanded( flex: 10, child: Row( children: [ CatIcon(imagePath: (Cat2Ico(post.kategoria!.toString()))), Checkbox( value: Int2Bool(post.status!.toInt()), onChanged: (value) { setState(() { post.status = Bool2Int(value!); }); saveStatus(post.nazwa!, post.status!, index); posts.sort(customCompare); }, ), ], ), ), ], ), ), ], ), ), ); }, ); }
更新1:我已更新源代码,将ListView.remove相关代码移至removeItem函数中。
更新2:以下是修改后的最终代码:
@override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.grey[100], floatingActionButton: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ FloatingActionButton.extended( heroTag: "fab1", onPressed: () { print('---> addList()'); // addList(); }, icon: const Icon(Icons.add_circle_outline), label: const Text('Dodaj'), ), if (showButton) FloatingActionButton.extended( heroTag: "fab2", onPressed: () { removeItem(itemName).then((value){ setState((){ itemToRemove = true; }); }); setState(() => showButton = false); }, icon: const Icon(Icons.delete), label: const Text('Usuń'), ), ], ), appBar: AppBar( backgroundColor: Colors.grey[900], title: const Text('Lista zakupowa'), actions: [ IconButton( onPressed: signUserOut, icon: const Icon(Icons.logout), ), ], ), body: Center( child: FutureBuilder<List<PostListDetails>>( future: postsFuture, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const CircularProgressIndicator(); } else if (snapshot.hasData) { return buildPosts(snapshot.data!); } else { return const Text("Brak danych..."); } }, ), ), ); } @override Widget buildPosts(List<PostListDetails> posts) { if (itemToRemove) { posts.removeWhere((element) => element.nazwa == itemName); itemToRemove=false; } return ListView.builder( itemCount: posts.length, itemBuilder: (context, index) { final post = posts[index]; int customCompare(PostListDetails a, PostListDetails b) { if (a.status != b.status) { return a.status!.toInt() - b.status!.toInt(); } final int categoryCompare = a.kategoria.toString().compareTo(b.kategoria.toString()); if (categoryCompare != 0) { return categoryCompare; } return a.nazwa.toString().compareTo(b.nazwa.toString()); } return GestureDetector( onLongPress: () { itemName = post.nazwa!; itemIndex = index; setState(() => showButton = true); }, child: Container( color: post.status! % 2 == 1 ? Colors.grey[100] : Colors.white, margin: const EdgeInsets.symmetric(vertical: 0.5, horizontal: 0), padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 15), height: 50, width: double.maxFinite, child: Row( children: [ Expanded( flex: 8, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( post.nazwa!, textAlign: TextAlign.left, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 15, color: Colors.black), ), Text( '${post.waga!.toString()} g.', textAlign: TextAlign.left, style: const TextStyle(fontWeight: FontWeight.normal, fontSize: 15, color: Colors.grey), ), ], ), ), Expanded( flex: 2, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Expanded( flex: 0, child: Row(), ), Expanded( flex: 10, child: Row( children: [ CatIcon(imagePath: (Cat2Ico(post.kategoria!.toString()))), Checkbox( value: Int2Bool(post.status!.toInt()), onChanged: (value) { setState(() { post.status = Bool2Int(value!); }); saveStatus(post.nazwa!, post.status!, index); posts.sort(customCompare); }, ), ], ), ), ], ), ), ], ), ), ); }, ); }
内容的提问来源于stack exchange,提问作者bzc0fq
相关产品推荐
相关产品推荐

