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

无法从其他Widget调用Widget,但可从Main调用的问题排查

问题描述

我正在开发一个简易计时器应用,通过滑块设置计时时长,点击「开始」按钮启动倒计时,点击「停止」按钮重置并停止计时。拆分了三个组件:timer_model(继承自ChangeNotifier)、timer_control和timer_view,后两者都通过Consumer<TimerModel>监听状态变化。

遇到的异常情况:

  • 将main函数中home设为TimerControl时,代码可正常调试运行
  • 设为TimerView时直接崩溃,无法调试
  • 注释掉TimerView中的TimerControl组件后,代码又能正常查看和调试,不清楚问题根源
代码示例

主文件

import 'package:controller_ui/models/timer_model.dart';
import 'package:flutter/material.dart';
import 'views/timer_view.dart';
import 'package:provider/provider.dart';

void main() {
  runApp(ChangeNotifierProvider(
    create: (context) => TimerModel(),
    child: const MyApp(),
  ));
}

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: TimerView(),
    );
  }
}

Model层(timer_model.dart)

import 'dart:async';
import 'package:flutter/material.dart';

class TimerModel extends ChangeNotifier {
  Timer? timer;
  double userSetTime = 10;
  final int maxTimeSeconds = 180;
  int timerSetTime = 10;

  void setTime(int seconds) {
    userSetTime = seconds.toDouble();
    notifyListeners();
  }

  void startCountdown() {
    if (timer != null && timer!.isActive) return;

    timer = Timer.periodic(const Duration(seconds: 1), (timer) {
      if (timerSetTime > 0) {
        timerSetTime--;
      } else {
        timer.cancel();
      }
    });
    notifyListeners();
  }

  void resetCountdown() {
    timerSetTime =
        userSetTime.round(); // reset to initial value or any desired value
    timer?.cancel();
    notifyListeners();
  }
}

Control组件(timer_control.dart)

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../models/timer_model.dart';

class TimerControl extends StatefulWidget {
  const TimerControl({super.key});

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

class TimerControlState extends State<TimerControl> {
  @override
  Widget build(BuildContext context) {
    return Consumer<TimerModel>(
      builder: (context, value, child) {
        return Scaffold(
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                CircleAvatar(
                  radius: 100,
                  backgroundColor: const Color.fromARGB(255, 1, 12, 61),
                  child: Text(
                    value.userSetTime.round().toString(),
                    style: const TextStyle(fontSize: 40, color: Colors.white),
                  ),
                ),
                Slider(
                  value: value.userSetTime,
                  max: value.maxTimeSeconds.toDouble(),
                  label: value.userSetTime.round().toString(),
                  onChanged: (double seconds) {
                    value.setTime(seconds.round());
                  },
                ),
              ],
            ),
          ),
        );
      },
    );
  }
}

View组件(timer_view.dart)

import 'package:flutter/material.dart';
import '../widgets/timer_control.dart';
import 'package:provider/provider.dart';
import '../models/timer_model.dart';

class TimerView extends StatefulWidget {
  const TimerView({super.key});

  @override
  State<TimerView> createState() => _TimerViewState();
}

class _TimerViewState extends State<TimerView> {
  @override
  Widget build(BuildContext context) {
    return Consumer<TimerModel>(
        builder: (context, value, child) => Scaffold(
              body: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  TimerControl(),
                  const SizedBox(
                    width: 200,
                  ),
                  Column(
                    children: [
                      ElevatedButton(
                          onPressed: value.startCountdown,
                          child: const Text('Start')),
                      ElevatedButton(
                          onPressed: value.resetCountdown,
                          child: const Text('Stop')),
                    ],
                  )
                ],
              ),
            ));
  }
}
问题根源与修复方案

核心问题

  1. 嵌套Scaffold冲突:TimerControl自身返回了一个Scaffold,而TimerView也返回了一个Scaffold,嵌套Scaffold会导致Flutter布局结构混乱,触发渲染异常。
  2. 冗余Consumer监听:TimerView已经通过Consumer获取了TimerModel,TimerControl内部重复使用Consumer属于冗余操作,且可能引发上下文监听冲突。

修复步骤

1. 修改TimerControl组件

移除内部的Scaffold和Consumer,改为直接从上下文获取TimerModel:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../models/timer_model.dart';

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

  @override
  Widget build(BuildContext context) {
    final timerModel = Provider.of<TimerModel>(context);
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          CircleAvatar(
            radius: 100,
            backgroundColor: const Color.fromARGB(255, 1, 12, 61),
            child: Text(
              timerModel.userSetTime.round().toString(),
              style: const TextStyle(fontSize: 40, color: Colors.white),
            ),
          ),
          Slider(
            value: timerModel.userSetTime,
            max: timerModel.maxTimeSeconds.toDouble(),
            label: timerModel.userSetTime.round().toString(),
            onChanged: (double seconds) {
              timerModel.setTime(seconds.round());
            },
          ),
        ],
      ),
    );
  }
}

2. 修正TimerView布局细节

把垂直布局中的水平间距SizedBox(width:200)改为垂直间距SizedBox(height:40),避免布局错位:

import 'package:flutter/material.dart';
import '../widgets/timer_control.dart';
import 'package:provider/provider.dart';
import '../models/timer_model.dart';

class TimerView extends StatefulWidget {
  const TimerView({super.key});

  @override
  State<TimerView> createState() => _TimerViewState();
}

class _TimerViewState extends State<TimerView> {
  @override
  Widget build(BuildContext context) {
    return Consumer<TimerModel>(
        builder: (context, value, child) => Scaffold(
              body: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  TimerControl(),
                  const SizedBox(height: 40),
                  Column(
                    children: [
                      ElevatedButton(
                          onPressed: value.startCountdown,
                          child: const Text('Start')),
                      const SizedBox(height: 10),
                      ElevatedButton(
                          onPressed: value.resetCountdown,
                          child: const Text('Stop')),
                    ],
                  )
                ],
              ),
            ));
  }
}

3. 修复Model层倒计时逻辑

startCountdown方法缺少启动时同步最新设置时间的逻辑,且每秒倒计时时未通知UI更新,补充后代码:

void startCountdown() {
  if (timer != null && timer!.isActive) return;

  // 启动前同步最新设置的时间
  timerSetTime = userSetTime.round();
  timer = Timer.periodic(const Duration(seconds: 1), (timer) {
    if (timerSetTime > 0) {
      timerSetTime--;
      notifyListeners(); // 每秒更新时通知UI
    } else {
      timer.cancel();
    }
  });
  notifyListeners();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 00:50:25