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

Flutter计算器应用调用calcBase方法触发Null异常求助

Flutter计算器应用页面传参空指针异常解决

问题描述

使用Flutter和Dart开发计算器类应用,单页面运行时可正常展示计算结果,但点击“Calculate”按钮跳转至结果页面时抛出异常:

The method 'calcBase' was called on null. Receiver: null Tried calling: calcBase()

推测是对象未初始化导致,尝试AI工具和查阅资料后仍未解决,寻求帮助。

应用结构

  • data_input.dart中的DataPageState类:负责存储计算所需变量,包含calcBase计算方法
  • calculate_button.dart中的Calculate组件:触发计算并跳转至ResultPage
  • result_page.dart的ResultPage:用于展示计算结果

相关代码

data_input.dart

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

  @override
  DataPageState createState() => DataPageState();
}

class DataPageState extends State<DataPage> {
  int cost = 0;

  String dropDown = '48';
  String user = '48';
  String selected = '';

  List<String> values = [
    '1',
    '2',
    '3',
    '4',
    '5',
    '6',
  ];

  void getDropDownItem() {
    setState(() {
      selected = dropDown;
    });
  }

  // for UI
  var dL = 0;
  var wL = 0;
  var cC = 0;
  var mT = 0;

  // to hold base data
  final baseValue = const [
    '1',
    '2',
    '3',
    '4',
    '5',
    '6',
  ];
  //Holds base lay values at positions [0]blDL, [1]blWL, [2]blCC, [3]blMT
  final Map<String, List<int>> blValues = {
    '1': [10, 20, 30, 40],
    '2': [50, 60, 70, 80],
    '3': [90, 100, 110, 120],
    '4': [130, 140, 150, 160],
    '5': [170, 180, 190, 200],
    '6': [210, 220, 230, 240],
  };

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: <Widget>[
          SliverAppBar(
            floating: true,
            pinned: true,
            expandedHeight: 200.0,
            centerTitle: true,
            title: Image.asset(
              'assets/images/ppLogo.png',
              height: 65.0,
              width: 200.0,
              fit: BoxFit.contain,
              alignment: Alignment.center,
            ),
            flexibleSpace: Stack(
              children: [
                Positioned.fill(
                    child: Image.asset(
                  'assets/images/inApp.jpg',
                  fit: BoxFit.cover,
                ))
              ],
            ),
          ),
          SliverToBoxAdapter(
            child: Container(
              color: Colors.black26,
              child: Padding(
                padding: const EdgeInsets.symmetric(
                  vertical: 16.0,
                  horizontal: 32.0,
                ),
                child: Column(
                  children: [
                    Padding(
                      padding: const EdgeInsets.only(
                          left: 0.0, top: 8.0, right: 0.0, bottom: 8.0),
                      child: DropdownButtonFormField(
                          decoration: const InputDecoration(
                              labelStyle: TextStyle(
                                  color: Colors.white70, fontSize: 24.0),
                              labelText: 'Drop Down Values'),
                          value: dropDown,
                          items: values
                              .map((String value) => DropdownMenuItem(
                                    value: value,
                                    child: Text(value),
                                  ))
                              .toList(),
                          onChanged: (data) => setState(() {
                                dropDown = data!;
                                getDropDownItem();
                              })),
                    ),
                    Padding(
                      padding: const EdgeInsets.only(
                          left: 0.0, top: 0.0, right: 0.0, bottom: 8.0),
                      child: TextField(
                        onChanged: (val) {
                          dL = int.parse(val);
                        },
                        decoration: const InputDecoration(
                          labelText: "DL",
                          labelStyle: TextStyle(
                            color: Colors.white70,
                            fontSize: 18.0,
                          ),
                          hintText: "Enter Your DL Value",
                          hintStyle: TextStyle(
                            color: Colors.lightGreen,
                            fontSize: 10.0,
                          ),
                        ),
                        textInputAction: TextInputAction.next,
                        keyboardType: TextInputType.number,
                        inputFormatters: <TextInputFormatter>[
                          FilteringTextInputFormatter.digitsOnly
                        ],
                      ),
                    ),
                    Padding(
                      padding: const EdgeInsets.only(
                          left: 0.0, top: 0.0, right: 0.0, bottom: 8.0),
                      child: TextField(
                        onChanged: (val) {
                          wL = int.parse(val);
                        },
                        decoration: const InputDecoration(
                          labelText: "WL",
                          labelStyle: TextStyle(
                            color: Colors.white70,
                            fontSize: 18.0,
                          ),
                          hintText: "Enter Your WL Values",
                          hintStyle: TextStyle(
                            color: Colors.lightGreen,
                            fontSize: 10.0,
                          ),
                        ),
                        textInputAction: TextInputAction.next,
                        keyboardType: TextInputType.number,
                        inputFormatters: <TextInputFormatter>[
                          FilteringTextInputFormatter.digitsOnly
                        ],
                      ),
                    ),
                    Padding(
                      padding: const EdgeInsets.only(
                          left: 0.0, top: 0.0, right: 0.0, bottom: 8.0),
                      child: TextField(
                        onChanged: (val) {
                          cC = int.parse(val);
                        },
                        decoration: const InputDecoration(
                          labelText: "CC",
                          labelStyle: TextStyle(
                            color: Colors.white70,
                            fontSize: 18.0,
                          ),
                          hintText: "Enter Your CC Value",
                          hintStyle: TextStyle(
                            color: Colors.lightGreen,
                            fontSize: 10.0,
                          ),
                        ),
                        textInputAction: TextInputAction.next,
                        keyboardType: TextInputType.number,
                        inputFormatters: <TextInputFormatter>[
                          FilteringTextInputFormatter.digitsOnly
                        ],
                      ),
                    ),
                    Padding(
                      padding: const EdgeInsets.only(
                          left: 0.0, top: 0.0, right: 0.0, bottom: 24.0),
                      child: TextField(
                        onChanged: (val) {
                          mT = int.parse(val);
                        },
                        decoration: const InputDecoration(
                          labelText: "MT",
                          labelStyle: TextStyle(
                            color: Colors.white70,
                            fontSize: 18.0,
                          ),
                          hintText: "Enter Your MT Value",
                          hintStyle: TextStyle(
                            color: Colors.lightGreen,
                            fontSize: 10.0,
                          ),
                        ),
                        textInputAction: TextInputAction.next,
                        keyboardType: TextInputType.number,
                        inputFormatters: <TextInputFormatter>[
                          FilteringTextInputFormatter.digitsOnly
                        ],
                      ),
                    ),
                    const Calculate(),
                    const Padding(
                        padding: EdgeInsets.only(
                            left: 0.0, top: 8.0, right: 0.0, bottom: 8.0),
                        child: Text(
                          'Text.',
                          style: TextStyle(
                              fontSize: 12.0, fontStyle: FontStyle.italic),
                        )),
                  ],
                ),
              ),
            ),
          ),
          SliverFillRemaining(
            child: Container(color: Colors.black26),
          )
        ],
      ),
      bottomNavigationBar: const BottomNav(),
    );
  }

  // This function calculates the base lay cost.
 int calcBase() {
    // Calculation based on the values that the user has entered in the TextFields.
    num cost = 0;

    // Get the values from the DataPage class.
    String dropDown = DataPageState.of(context).dropDown;
    var dL = DataPageState.of(context).dL;
    var wL = DataPageState.of(context).wL;
    var cC = DataPageState.of(context).cC;
    var mT = DataPageState.of(context).mT;

    // Calculate the base for each category.
    num dLB = blValues[dropDown]![0] * dL;
    num wLB = blValues[dropDown]![1] * wL;
    num cCB = blValues[dropDown]![2] * cC;
    num mTB = blValues[dropDown]![3] * mT;

    // Add the base for each category to get the total cost.
    cost = dLB + wLB + cCB + mTB;

    return cost.toInt();
  }
  static of(BuildContext context) {
  }
}

calculate_button.dart

class Calculate extends StatelessWidget {
  const Calculate({Key? key}) : super(key: key);

  Future<void> showOverlay(BuildContext context) async {
    OverlayState overlayState = Overlay.of(context);
    OverlayEntry overlayEntry = OverlayEntry(
        opaque: true,
        builder: (context) =>
            Center(child: Image.asset("assets/images/pipeSqueak.gif")));

    overlayState.insert(overlayEntry);

    return Future.delayed(const Duration(milliseconds: 3000), () {
      overlayEntry.remove();
    });
  }

  @override
  Widget build(BuildContext context) {
    return Builder(
        builder: (buttonContext) => ElevatedButton(
            style: ButtonStyle(
              backgroundColor:
                  MaterialStateProperty.all<Color>(Colors.grey[600]!),
              foregroundColor:
                  MaterialStateProperty.all<Color>(Colors.red[900]!),
              shadowColor:
                  MaterialStateProperty.all<Color>(Colors.lightGreen[400]!),
            ),
            onPressed: () {
              showOverlay(context);
              var cost = DataPageState.of(context).calcBase();
                  Navigator.push(
                    context,
                    MaterialPageRoute(
                      builder: (context) =>
                          ResultPage(cost: cost),
                    ),
                  );
              },
          child: const Text('Calculate'),
        ));
  }
}

result_page.dart

class ResultPage extends StatelessWidget {
  final int cost;

  const ResultPage({Key? key, required this.cost}) : super(key: key);


  void customLaunch(command) async {
    if (await canLaunchUrl(command)) {
      await launchUrl(command);
    } else {
      throw 'Unable to complete $command';
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: <Widget>[
          SliverAppBar(
            automaticallyImplyLeading: false,
            floating: false,
            pinned: true,
            expandedHeight: 100.0,
            title: Image.asset(
              'assets/images/Blank.png',
              height: 0.0,
              width: 0.0,
              fit: BoxFit.contain,
              alignment: Alignment.bottomCenter,
            ),
            flexibleSpace: Stack(
              children: [
                Positioned.fill(
                    child: Image.asset('assets/images/resultAppBar.png',
                        fit: BoxFit.cover))
              ],
            ),
          ),
          SliverToBoxAdapter(
              child: Container(
            color: Colors.black26,
            child: Padding(
              padding: const EdgeInsets.symmetric(
                vertical: 16.0,
                horizontal: 22.0,
              ),
              child: Column(
                children: [
                  const SizedBox(height: 24.0),
                  const Text(
                    'Text:',
                    textAlign: TextAlign.justify,
                    style:
                        TextStyle(fontSize: 14.0, fontWeight: FontWeight.bold),
                  ),
                  Text(
                    '$cost',
                    textAlign: TextAlign.center,
                    style: const TextStyle(
                      fontSize: 25.0,
                      decoration: TextDecoration.underline,
                    ),
                  ),
                 
//Remaining code is text

已尝试的无效方案

修改calcBase为void方法,调整of方法写法,但仍出现空指针异常。

最终解决方法

问题根源在于成本变量的计算和传递方式,调整后代码如下:

修改后的DataPageState类

void calcBase() {
    setState(() {
      int rng = min + r.nextInt(max - min);
      romRandom = (rng / 100.0);

      final selectedBlValues =
          blValues[dropDown];
      if (selectedBlValues != null) {
        rom = (dL * selectedBlValues[0] +
            (wL * selectedBlValues[1]) +
            (cC * selectedBlValues[2]) +
            (mT * selectedBlValues[3]));
      }

      cost = (rom * romRandom).toInt();
    });
}

static DataPageState of(BuildContext context) {
    return context.findRootAncestorStateOfType<DataPageState>()!;
}

修改后的Calculate组件

DataPageState.of(context).calcBase();
var cost = DataPageState.of(context).cost;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 04:37:02