Flutter问题:ListView卡片计数器需独立计数而非全局同步
点击按钮时所有卡片同步计数,需实现单卡独立计数
开发Flutter应用时,点击卡片中的“Go”按钮,所有卡片的计数器会同步变化,希望每个卡片的计数器能独立计数,实现每个卡片的计数器独立初始化及计数,而非全局同步。
原代码
import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:ziker/text_format.dart'; class TestPage extends StatefulWidget { @override State<TestPage> createState() => _TestPageState(); } class _TestPageState extends State<TestPage> { // Create a list of texts final List<String> texts = [ "Hello world", "Hello world!2" ]; final List<int> subTexts = [ 1, 2, ]; int counter = 0; @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.grey[200], appBar: AppBar( backgroundColor: Colors.transparent, elevation: 0, title: Text( "أذكار الصباح", textDirection: TextDirection.rtl, style: GoogleFonts.arefRuqaa( fontSize: 24, fontWeight: FontWeight.w700, color: Colors.black, ), ), centerTitle: true, ), body: Container( padding: EdgeInsets.all( 25, ), child: ListView.builder( // Set the length of the list itemCount: texts.length, // Return a Card widget for each item itemBuilder: (context, index) { return Padding( padding: const EdgeInsets.symmetric( vertical: 8, ), child: Card( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), //set border radius more than 50% of height and width to make circle ), // Use a Column to arrange the text and the buttons vertically child: Container( padding: const EdgeInsets.all(25.0), color: Colors.amber, child: Column( children: [ // Display the text inside the card AmiriText( text: texts[index], fontS: 25, textDirection: TextDirection.rtl, ), SizedBox( height: 25, ), CircleAvatar( child: Text( subTexts[index].toString(), ), ), SizedBox( height: 25, ), // Use a Row to display the two buttons horizontally Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: <Widget>[ ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Color(0xFF086788), foregroundColor: Color(0xFF9CAFB7), shadowColor: Colors.grey[400], elevation: 3, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( 10.0, ), ), minimumSize: Size(100, 40), ), child: AmiriText( text: "return back", fontS: 18, color: Colors.white, ), onPressed: () { setState(() { if (counter > 0) { counter--; } }); }, ), Text( counter.toString(), style: TextStyle( fontSize: 18, fontWeight: FontWeight.w700, ), ), ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Color(0xFF062726), foregroundColor: Color(0xFF66A182), shadowColor: Colors.grey[400], elevation: 3, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( 10.0, ), ), minimumSize: Size(100, 40), ), child: AmiriText( text: "Go", fontS: 18, color: Colors.white, ), onPressed: () { setState(() { counter++; }); }, ), ], ), ], ), ), ), ); }, ), ), ); } }
问题原因
当前代码使用了全局单个counter变量,所有卡片的计数器都绑定这个变量,所以点击任意卡片的按钮都会让所有计数器同步变化。要实现独立计数,需要给每个卡片分配单独的计数器。
修改方案
- 将全局
int counter替换为计数器列表List<int> counters,初始化时根据卡片数量生成对应数量的初始值(比如初始为0)。 - 按钮点击时,操作对应索引的计数器值。
- 显示计数器时,读取对应索引的计数器值。
修改后的完整代码
import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:ziker/text_format.dart'; class TestPage extends StatefulWidget { @override State<TestPage> createState() => _TestPageState(); } class _TestPageState extends State<TestPage> { final List<String> texts = [ "Hello world", "Hello world!2" ]; final List<int> subTexts = [1, 2]; // 用列表存储每个卡片的独立计数器,初始值都为0 late List<int> counters; @override void initState() { super.initState(); // 根据卡片数量初始化计数器列表 counters = List.generate(texts.length, (index) => 0); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.grey[200], appBar: AppBar( backgroundColor: Colors.transparent, elevation: 0, title: Text( "أذكار الصباح", textDirection: TextDirection.rtl, style: GoogleFonts.arefRuqaa( fontSize: 24, fontWeight: FontWeight.w700, color: Colors.black, ), ), centerTitle: true, ), body: Container( padding: const EdgeInsets.all(25), child: ListView.builder( itemCount: texts.length, itemBuilder: (context, index) { return Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: Card( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), child: Container( padding: const EdgeInsets.all(25.0), color: Colors.amber, child: Column( children: [ AmiriText( text: texts[index], fontS: 25, textDirection: TextDirection.rtl, ), const SizedBox(height: 25), CircleAvatar( child: Text(subTexts[index].toString()), ), const SizedBox(height: 25), Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: <Widget>[ ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF086788), foregroundColor: const Color(0xFF9CAFB7), shadowColor: Colors.grey[400], elevation: 3, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10.0), ), minimumSize: const Size(100, 40), ), child: const AmiriText( text: "return back", fontS: 18, color: Colors.white, ), onPressed: () { setState(() { if (counters[index] > 0) { counters[index]--; } }); }, ), Text( counters[index].toString(), style: const TextStyle( fontSize: 18, fontWeight: FontWeight.w700, ), ), ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF062726), foregroundColor: const Color(0xFF66A182), shadowColor: Colors.grey[400], elevation: 3, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10.0), ), minimumSize: const Size(100, 40), ), child: const AmiriText( text: "Go", fontS: 18, color: Colors.white, ), onPressed: () { setState(() { counters[index]++; }); }, ), ], ), ], ), ), ), ); }, ), ), ); } }
内容的提问来源于stack exchange,提问作者Icarus
相关产品推荐
相关产品推荐

