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

Dart函数传入变量后无法更新计数器问题求助

问题描述

我正在创建一个可在应用中复用的Dart函数,该函数包含两个按钮,关联本地计数器(localCounter)和全局计数器(GlobalCounter)。当直接在代码中写入整数时功能正常,但将其作为函数传入变量后,按钮可点击但计数器无法增减,且代码无报错。

相关代码如下:

import 'package:flutter/material.dart';

void main() {
  runApp(
    const MyApp(),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        backgroundColor: Colors.black,
        body: SafeArea(
          child: MainPage(),
        ),
      ),
    );
  }
}

class MainPage extends StatefulWidget {
  const MainPage({Key? key}) : super(key: key);

  @override
  State<MainPage> createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
int TP1LeftCounter = 0;                                      //localCounter
int movpLeftCounter = 0;                                     //globalCounter


Row TpScores(int localCounter, int globalCounter) {          //Dart Function I'm trying to create
  return Row(
    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
    children: [
      ClipRRect(
        borderRadius: BorderRadius.circular(5.0),
        child: InkWell(
          onTap: () {
            setState(() {
              if (localCounter > 0) localCounter--;
              if (globalCounter > 0) globalCounter--;
            });
          },
          child: Container(
            child: Icon(Icons.remove, color: Colors.white),
            width: 25.0,
            height: 35.0,
            color: Colors.blueGrey[900],
          ),
        ),
      ),
      Container(
        child: Text(
          '$localCounter',
          style: TextStyle(
            fontFamily: 'SourceSansPro',
            fontSize: 40.0,
            color: Colors.white,
            fontWeight: FontWeight.bold,
          ),
        ),
      ),
      ClipRRect(
        borderRadius: BorderRadius.circular(5.0),
        child: InkWell(
          onTap: () {
            setState(() {
              if (localCounter < 12) localCounter++;
              if (globalCounter < 12) globalCounter++;
            });
          },
          child: Container(
            child: Icon(Icons.add, color: Colors.white),
            width: 25.0,
            height: 35.0,
            color: Colors.blueGrey[900],
          ),
        ),
      ),
    ],
  );
}

在build方法中调用该函数:

Expanded(
  child: Container(
    height: 50.0,
    child: TpScores(TP1LeftCounter, movpLeftCounter),
  ),
),

点击按钮后计数器没有增减,但按钮可正常响应,请问我遗漏了什么?


问题原因与解决方案

核心问题:Dart的值传递特性

Dart中int是值类型,当你把TP1LeftCounter和movpLeftCounter传入TpScores函数时,传递的是变量的副本,而非原变量的引用。按钮点击事件里修改的localCounter和globalCounter只是函数内部的临时变量,和State中的原变量完全无关。哪怕调用setState,更新的也只是副本的值,原变量根本没变化,UI自然不会更新。

解决方案:通过回调函数修改原变量

要让函数能修改State中的变量,需把修改逻辑通过回调函数传递进去,让函数内部的按钮点击事件触发回调,直接操作State中的原变量。

修改后的代码示例

  1. 重构TpScores函数,增加回调参数:
Row TpScores(
  int currentValue,
  VoidCallback onIncrement,
  VoidCallback onDecrement,
) {
  return Row(
    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
    children: [
      ClipRRect(
        borderRadius: BorderRadius.circular(5.0),
        child: InkWell(
          onTap: onDecrement,
          child: Container(
            child: const Icon(Icons.remove, color: Colors.white),
            width: 25.0,
            height: 35.0,
            color: Colors.blueGrey[900],
          ),
        ),
      ),
      Container(
        child: Text(
          '$currentValue',
          style: const TextStyle(
            fontFamily: 'SourceSansPro',
            fontSize: 40.0,
            color: Colors.white,
            fontWeight: FontWeight.bold,
          ),
        ),
      ),
      ClipRRect(
        borderRadius: BorderRadius.circular(5.0),
        child: InkWell(
          onTap: onIncrement,
          child: Container(
            child: const Icon(Icons.add, color: Colors.white),
            width: 25.0,
            height: 35.0,
            color: Colors.blueGrey[900],
          ),
        ),
      ),
    ],
  );
}
  1. 调用函数时传入对应的回调逻辑:
Expanded(
  child: Container(
    height: 50.0,
    child: TpScores(
      TP1LeftCounter,
      // 递增回调:同时修改两个计数器
      () {
        setState(() {
          if (TP1LeftCounter < 12) TP1LeftCounter++;
          if (movpLeftCounter < 12) movpLeftCounter++;
        });
      },
      // 递减回调:同时修改两个计数器
      () {
        setState(() {
          if (TP1LeftCounter > 0) TP1LeftCounter--;
          if (movpLeftCounter > 0) movpLeftCounter--;
        });
      },
    ),
  ),
),

额外优化:封装为独立Widget(更符合Flutter最佳实践)

如果要做可复用的组件,推荐封装成独立的StatelessWidget,状态管理更清晰,复用性更强:

class ScoreCounter extends StatelessWidget {
  final int currentValue;
  final VoidCallback onIncrement;
  final VoidCallback onDecrement;

  const ScoreCounter({
    super.key,
    required this.currentValue,
    required this.onIncrement,
    required this.onDecrement,
  });

  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: [
        ClipRRect(
          borderRadius: BorderRadius.circular(5.0),
          child: InkWell(
            onTap: onDecrement,
            child: Container(
              child: const Icon(Icons.remove, color: Colors.white),
              width: 25.0,
              height: 35.0,
              color: Colors.blueGrey[900],
            ),
          ),
        ),
        Container(
          child: Text(
            '$currentValue',
            style: const TextStyle(
              fontFamily: 'SourceSansPro',
              fontSize: 40.0,
              color: Colors.white,
              fontWeight: FontWeight.bold,
            ),
          ),
        ),
        ClipRRect(
          borderRadius: BorderRadius.circular(5.0),
          child: InkWell(
            onTap: onIncrement,
            child: Container(
              child: const Icon(Icons.add, color: Colors.white),
              width: 25.0,
              height: 35.0,
              color: Colors.blueGrey[900],
            ),
          ),
        ),
      ],
    );
  }
}

调用方式和之前一致:

Expanded(
  child: Container(
    height: 50.0,
    child: ScoreCounter(
      currentValue: TP1LeftCounter,
      onIncrement: () {
        setState(() {
          if (TP1LeftCounter < 12) TP1LeftCounter++;
          if (movpLeftCounter < 12) movpLeftCounter++;
        });
      },
      onDecrement: () {
        setState(() {
          if (TP1LeftCounter > 0) TP1LeftCounter--;
          if (movpLeftCounter > 0) movpLeftCounter--;
        });
      },
    ),
  ),
),

内容的提问来源于stack exchange,提问作者Nomad09

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 00:40:42