You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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变量,所有卡片的计数器都绑定这个变量,所以点击任意卡片的按钮都会让所有计数器同步变化。要实现独立计数,需要给每个卡片分配单独的计数器。

修改方案

  1. 将全局int counter替换为计数器列表List<int> counters,初始化时根据卡片数量生成对应数量的初始值(比如初始为0)。
  2. 按钮点击时,操作对应索引的计数器值。
  3. 显示计数器时,读取对应索引的计数器值。

修改后的完整代码

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 18:25:07