状态更改后 UI 未更新

问题描述 投票:0回答:1

我陷入了一个奇怪的境地。交叉检查了所有参考资料。问题是我的计时器没有更新 modelBottomSheet。 这是我的锻炼追踪器

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

  @override
  State<WorkOutTracker> createState() => _WorkOutTrackerState();
}

class _WorkOutTrackerState extends State<WorkOutTracker> {
  final WorkoutBloc workoutBloc = WorkoutBloc();
  String elapsedTime = "0s";
  late Timer timer;

  void updateElapsedTime(Timer timer) {
    workoutBloc.add(StartWorkout(timer: timer));
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: BlocConsumer<WorkoutBloc, WorkoutState>(
        bloc: workoutBloc,
        listenWhen: (previous, current) => current is WorkoutActionState,
        buildWhen: (previous, current) => current is! WorkoutActionState,
        listener: (context, state) {
          // TODO: implement listener
          print("sdsd");
        },
        builder: (context, state) {
          return Scaffold(
            body: Column(
              children: [
                Expanded(
                  child: SingleChildScrollView(
                    child: Column(
                      children: [
                        _buildStartWorkoutButton(),
                      ],
                    ),
                  ),
                ),
                if (state is Workingout) _buildResumeCancelButtons(),
              ],
            ),
          );
        },
      ),
    );
  }

  Widget _buildStartWorkoutButton() {
    return Column(
      children: [
        const Align(
          alignment: Alignment.centerLeft,
          child: Padding(
            padding: EdgeInsets.all(8.0),
            child: Text(
              'Start workout',
              style: TextStyle(
                color: Colors.black,
                fontSize: 25,
                fontWeight: FontWeight.bold,
              ),
            ),
          ),
        ),
        Center(
          child: ElevatedButton(
            style: ButtonStyle(
              backgroundColor: MaterialStateProperty.all(Colors.blue),
              shape: MaterialStateProperty.all<RoundedRectangleBorder>(
                const RoundedRectangleBorder(
                  borderRadius: BorderRadius.all(Radius.circular(6.0)),
                ),
              ),
            ),
            child: const Text(
              'Start with new routine',
              style: TextStyle(color: Colors.black),
            ),
            onPressed: () => _onStartWorkoutButtonPressed(context),
          ),
        ),
      ],
    );
  }

  Widget _buildResumeCancelButtons() {
    return Container(
      decoration: BoxDecoration(
        border: Border.all(color: Colors.blueAccent),
      ),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: [
          ElevatedButton(
            style: ButtonStyle(
              backgroundColor: MaterialStateProperty.all(Colors.blue),
              shape: MaterialStateProperty.all<RoundedRectangleBorder>(
                const RoundedRectangleBorder(
                  borderRadius: BorderRadius.all(Radius.circular(6.0)),
                ),
              ),
            ),
            child: const Text(
              'Resume workout',
              style: TextStyle(color: Colors.black),
            ),
            onPressed: () => _onResumeWorkoutButtonPressed(context),
          ),
          ElevatedButton(
            style: ButtonStyle(
              backgroundColor: MaterialStateProperty.all(Colors.blue),
              shape: MaterialStateProperty.all<RoundedRectangleBorder>(
                const RoundedRectangleBorder(
                  borderRadius: BorderRadius.all(Radius.circular(6.0)),
                ),
              ),
            ),
            child: const Text(
              'Cancel workout',
              style: TextStyle(color: Colors.black),
            ),
            onPressed: () => _onCancelWorkoutButtonPressed(),
          ),
        ],
      ),
    );
  }

  void _onStartWorkoutButtonPressed(BuildContext context) {
    timer = Timer.periodic(
      const Duration(seconds: 1),
      (Timer t) {
        updateElapsedTime(t);
      },
    );
    showModalBottomSheet<dynamic>(
      isScrollControlled: true,
      context: context,
      builder: (BuildContext context) {
        return ExcerciseTracker();
      },
    );
  }

  void _onResumeWorkoutButtonPressed(BuildContext context) {
    showModalBottomSheet<dynamic>(
      isScrollControlled: true,
      context: context,
      builder: (BuildContext context) {
        return ExcerciseTracker();
      },
    );
  }

  void _onCancelWorkoutButtonPressed() {
    timer.cancel();
    workoutBloc.add(EndWorkout());
  }
}

请关注 _onStartWorkoutButtonPressed,这里我正在启动一个计时器并显示一个 modalBottomSheet。

下一个文件是 WorkoutBloc

class WorkoutBloc extends Bloc<WorkoutEvent, WorkoutState> {
  WorkoutBloc() : super(WorkoutInitial()) {
    on<StartWorkout>(startWorkout);
    on<EndWorkout>(endWorkout);
    on<ResumeWorkout>(resumeWorkout);
  }

  FutureOr<void> startWorkout(
      StartWorkout event, Emitter<WorkoutState> emit) async {
    //starting workout
    try {
      print(event.timer.tick);
      return emit(Workingout(second: event.timer.tick));
    } catch (e) {
      emit(Error());
    }
  }

  FutureOr<void> endWorkout(
      EndWorkout event, Emitter<WorkoutState> emit) async {
    try {
      return emit(EndWorkingout());
    } catch (e) {
      emit(Error());
    }
  }

  FutureOr<void> resumeWorkout(
      ResumeWorkout event, Emitter<WorkoutState> emit) {}
}

此文件在每次更改时都会产生“锻炼”状态。我已经通过 print 语句验证了它,并且工作正常。

还有最后一个文件

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

  @override
  State<ExcerciseTracker> createState() => _ExcerciseTrackerState();
}

class _ExcerciseTrackerState extends State<ExcerciseTracker> {
  final WorkoutBloc workoutBloc = WorkoutBloc();

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      height: MediaQuery.of(context).size.height * 0.85,
      child: BlocConsumer<WorkoutBloc, WorkoutState>(
        bloc: workoutBloc,
        listenWhen: (previous, current) => current is WorkoutActionState,
        buildWhen: (previous, current) => current is! WorkoutActionState,
        listener: (context, state) {
          // TODO: implement listener
          print("sdsd");
        },
        builder: (context, state) {
          print("BlocConsumer rebuilt with state: $state");
          return Column(
            children: [
              Padding(
                padding: const EdgeInsets.all(10.0),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    // Taken from here https://unicode.org/Public/emoji/1.0/emoji-data.txt
                    const Text(
                      '\u{1F525} 234 ',
                      style: TextStyle(
                          fontSize: 18.0, fontWeight: FontWeight.bold),
                    ),
                    Text(
                      _getFormattedElapsedTime(state).toString(),
                      style: const TextStyle(
                          fontSize: 18.0, fontWeight: FontWeight.bold),
                    ),
                    IconButton(
                      icon: const Icon(
                        Icons.close,
                        color: Colors.black,
                        size: 30.0,
                        semanticLabel:
                            'Text to announce in accessibility modes',
                      ),
                      onPressed: () {
                        Navigator.pop(context);
                      },
                    ),
                  ],
                ),
              ),
            ],
          );
        },
      ),
    );
  }

  String _getFormattedElapsedTime(WorkoutState state) {
    // Calculate elapsed time using the timer
    print(state.toString());
    int seconds = state is Workingout ? state.second : 10;
    int minutes = seconds ~/ 60;
    seconds %= 60;
    return '$minutes:${seconds.toString().padLeft(2, '0')}';
  }
}

这个文件就是问题所在,

print(state.toString());
只打印
Instance of 'WorkoutInitial'
并且没有获得锻炼状态。 有人可以向我解释一下为什么会发生这种情况吗? 谢谢。

flutter dart bloc
1个回答
0
投票

我遇到了类似的问题,如果我没记错的话,modalBottomSheet 或对话框正在创建自己的上下文,您无法在那里访问您的块。您必须将块传递给 modalBottomSheet(例如 ExcerciseTracker())作为参数,以确保您使用块的相同实例,否则您将使用所有初始值创建块的新实例。

也许它可以帮助你。

© www.soinside.com 2019 - 2024. All rights reserved.