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

Flutter Bloc模式下实现开关切换控制组件显隐的问题

问题解决方案

核心问题分析

你的代码目前存在两个关键问题:

  • Bloc每次emit新状态时,只传递部分字段,导致其他状态值丢失(比如触发StandardAirEvent后,standardAir和answer2会变为null)
  • 页面仍依赖本地standard变量,没有完全通过Bloc状态统一管理开关状态

修正步骤

1. 修正Bloc逻辑(保留完整状态)

每次emit新状态时,要基于当前状态的已有值进行更新,避免数据丢失:

class VelBloc extends Bloc<VelocityEvent, VelocityState> {
  VelBloc() : super(VelocityDataState(answer1: 0, answer2: 0, standardAir: true)) {
    on<InitialVelocityEvent>((event, emit) =>
        emit(VelocityDataState(answer1: 0, answer2: 0, standardAir: true)));
    
    on<StandardAirEvent>((event, emit) {
      final currentState = state as VelocityDataState;
      emit(VelocityDataState(
        answer1: sqrt(event.velocity) * 1.225,
        answer2: currentState.answer2,
        standardAir: currentState.standardAir,
      ));
    });
    
    on<AirDensityEvent>((event, emit) {
      final currentState = state as VelocityDataState;
      emit(VelocityDataState(
        answer1: currentState.answer1,
        answer2: sqrt(event.velocity) * event.airDensity,
        standardAir: currentState.standardAir,
      ));
    });
    
    on<IsStandard>((event, emit) {
      final currentState = state as VelocityDataState;
      emit(VelocityDataState(
        answer1: currentState.answer1,
        answer2: currentState.answer2,
        standardAir: event.standardAir,
      ));
    });
  }
}

2. 修正事件和状态的不可变性

移除must_be_immutable注释,使用final字段保证不可变性:

// Event 部分
part of 'vel_air_bloc.dart';

@immutable
abstract class VelocityEvent {}

class InitialVelocityEvent extends VelocityEvent {}

class StandardAirEvent extends VelocityEvent {
  final double velocity;
  StandardAirEvent({required this.velocity});
}

class AirDensityEvent extends VelocityEvent {
  final double velocity;
  final double airDensity;
  AirDensityEvent({required this.velocity, required this.airDensity});
}

class IsStandard extends VelocityEvent {
  final bool standardAir;
  IsStandard({required this.standardAir});
}

// State 部分
part of 'vel_air_bloc.dart';

@immutable
abstract class VelocityState {}

class VelocityDataState extends VelocityState {
  final double? answer1;
  final double? answer2;
  final bool? standardAir;
  
  VelocityDataState({this.answer1, this.answer2, this.standardAir});
}

3. 页面中用Bloc状态控制开关和组件显隐

移除本地standard变量,直接从Bloc状态获取值,开关切换时触发事件更新状态:

class _VelocityAirState extends State<VelocityAir> {
  FirebaseServices firebaseServices = FirebaseServices();
  String title = 'Velocity of Air';
  final TextEditingController _velocityController = TextEditingController();
  final TextEditingController _airDensity = TextEditingController();

  @override
  void initState() {
    super.initState();
    context.read<VelBloc>().add(InitialVelocityEvent());
  }

  @override
  void dispose() {
    _velocityController.dispose();
    _airDensity.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return BlocBuilder<VelBloc, VelocityState>(builder: (context, state) {
      if (state is VelocityDataState) {
        final isStandardAir = state.standardAir ?? true;
        return Scaffold(
          // 其他原有代码保持不变
          body: ListView(
            // 其他原有代码保持不变
            children: <Widget>[
              // 其他原有代码保持不变
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Card(
                  // 其他原有代码保持不变
                  child: Column(
                    // 其他原有代码保持不变
                    children: <Widget>[
                      Padding(
                          padding: const EdgeInsets.all(20.0),
                          child: CustomTextField(
                              onChanged: () {
                                if (_velocityController.text.trim().isNotEmpty && isStandardAir) {
                                  context.read<VelBloc>().add(StandardAirEvent(
                                      velocity: double.parse(_velocityController.text)));
                                }
                              },
                              // 其他原有属性保持不变
                          )),
                      Row(
                        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                        children: <Widget>[
                          const Text(
                            "Standard Air?",
                            style: TextStyle(
                                color: Colors.white,
                                fontWeight: FontWeight.w600),
                          ),
                          Padding(
                            padding: const EdgeInsets.all(8.0),
                            child: Text(
                              isStandardAir ? "Yes" : "No",
                              style: TextStyle(
                                  color: isStandardAir
                                      ? CupertinoColors.activeGreen
                                      : CupertinoColors.destructiveRed,
                                  fontWeight: FontWeight.w600),
                            ),
                          ),
                          Padding(
                            padding: const EdgeInsets.all(10.0),
                            child: CupertinoSwitch(
                                value: isStandardAir,
                                thumbColor: Colors.white,
                                trackColor: ColorConstants.borderColor,
                                activeColor: ColorConstants.lightGreen,
                                onChanged: (value) {
                                  context.read<VelBloc>().add(IsStandard(standardAir: value));
                                },
                            ),
                          ),
                        ],
                      ),
                      // 示例:根据开关状态控制组件显隐
                      if (!isStandardAir)
                        Padding(
                          padding: const EdgeInsets.all(20.0),
                          child: CustomTextField(
                            hintText: 'Enter air density',
                            controller: _airDensity,
                            // 其他属性自行补充
                          ),
                        ),
                    ],
                  ),
                ),
              ),
            ],
          ),
        );
      }
      return const SizedBox();
    });
  }
}

总结

  • 不需要在Bloc中使用void方法,严格遵循事件触发-状态更新的Bloc核心流程即可
  • 不要混用setState和Bloc,所有状态(包括开关状态)都交给Bloc统一管理,保证状态一致性
  • 每次emit新状态时,必须保留当前状态的其他字段值,避免状态丢失

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 01:15:33