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

Flutter中Cubit结合Stepper组件实现Radio/Dropdown状态更新

Flutter Cubit 处理 Radio/DropdownButton 状态更新最佳实践

核心逻辑

Cubit 状态管理的核心是通过事件触发状态变更,UI 监听状态自动重建。针对 Radio、DropdownButton 这类交互选择组件,需遵循以下流程:

  1. 定义包含选中状态的不可变状态类
  2. 在 Cubit 中实现处理选择事件的方法
  3. UI 层通过 BlocBuilder 绑定状态,渲染组件并触发事件

完整示例代码

1. 定义 Cubit 与状态类

import 'package:flutter_bloc/flutter_bloc.dart';

// 状态类:保存Radio和Dropdown的选中值
class SelectionState {
  final String selectedRadio;
  final String selectedDropdown;

  const SelectionState({
    required this.selectedRadio,
    required this.selectedDropdown,
  });

  // 生成新状态的复制方法(遵循不可变状态原则)
  SelectionState copyWith({
    String? selectedRadio,
    String? selectedDropdown,
  }) {
    return SelectionState(
      selectedRadio: selectedRadio ?? this.selectedRadio,
      selectedDropdown: selectedDropdown ?? this.selectedDropdown,
    );
  }
}

// Cubit类:处理选择事件并更新状态
class SelectionCubit extends Cubit<SelectionState> {
  SelectionCubit() : super(const SelectionState(
    selectedRadio: 'option1', // 默认选中项
    selectedDropdown: 'item1',
  ));

  // 更新Radio选中状态
  void updateRadio(String value) {
    emit(state.copyWith(selectedRadio: value));
  }

  // 更新Dropdown选中状态
  void updateDropdown(String value) {
    emit(state.copyWith(selectedDropdown: value));
  }
}

2. UI 层实现(绑定Cubit与组件)

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

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Cubit 选择组件示例')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // Radio 组件组
            const Text('Radio 选项'),
            BlocBuilder<SelectionCubit, SelectionState>(
              builder: (context, state) {
                return Column(
                  children: [
                    RadioListTile(
                      title: const Text('选项1'),
                      value: 'option1',
                      groupValue: state.selectedRadio,
                      onChanged: (value) {
                        if (value != null) {
                          context.read<SelectionCubit>().updateRadio(value);
                        }
                      },
                    ),
                    RadioListTile(
                      title: const Text('选项2'),
                      value: 'option2',
                      groupValue: state.selectedRadio,
                      onChanged: (value) {
                        if (value != null) {
                          context.read<SelectionCubit>().updateRadio(value);
                        }
                      },
                    ),
                  ],
                );
              },
            ),
            const SizedBox(height: 20),
            // DropdownButton 组件
            const Text('Dropdown 选项'),
            BlocBuilder<SelectionCubit, SelectionState>(
              builder: (context, state) {
                return DropdownButton<String>(
                  value: state.selectedDropdown,
                  items: const [
                    DropdownMenuItem(value: 'item1', child: Text('项目1')),
                    DropdownMenuItem(value: 'item2', child: Text('项目2')),
                    DropdownMenuItem(value: 'item3', child: Text('项目3')),
                  ],
                  onChanged: (value) {
                    if (value != null) {
                      context.read<SelectionCubit>().updateDropdown(value);
                    }
                  },
                  isExpanded: true,
                );
              },
            ),
            const SizedBox(height: 20),
            // 实时展示选中状态
            BlocBuilder<SelectionCubit, SelectionState>(
              builder: (context, state) {
                return Text(
                  '当前选中:Radio=${state.selectedRadio},Dropdown=${state.selectedDropdown}',
                  style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
                );
              },
            ),
          ],
        ),
      ),
    );
  }
}

3. 注入 Cubit(父Widget中)

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

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

  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (context) => SelectionCubit(),
      child: MaterialApp(
        home: const SelectionPage(),
      ),
    );
  }
}

关键注意事项

  • 不可变状态:状态类必须不可变,通过 copyWith 生成新状态,禁止直接修改原状态
  • 精准重建:仅用 BlocBuilder 包裹需要更新的组件,避免全局重建浪费性能
  • 事件触发:组件的 onChanged 回调中,通过 context.read<Cubit>() 获取实例并调用事件方法,不要直接操作状态
  • 默认值初始化:Cubit 初始状态需设置合理默认选中值,避免UI出现空状态异常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 21:25:22