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

如何在Flutter中使用CupertinoPicker实现多级联动选择器

实现公交站点联动选择方案

下面是修改后的完整代码,实现选择服务区域后,第二个CupertinoPicker自动切换对应城市的公交站点:

class _BookingPageState extends State<BookingPage> {
  FixedExtentScrollController scrollController = FixedExtentScrollController();

  final List<String> ibadanBusstop = [
    'Lead City Bus Stop',
    'Olorunsogo Bus Stop',
    'Challenge Bus Stop',
    'Mokola Bus Stop',
  ];

  final List<String> lagosBusstop = [
    'Jibowu Bus Stop',
    'Obalende Bus Stop',
  ];

  final List<String> serviceAreas = [
    'Lagos',
    'Oyo',
  ];

  // 合并索引变量,统一管理当前选中的公交站点索引
  int currentBusStopIndex = 0;
  int serviceAreaIndex = 0;

  // 根据选中区域动态返回对应公交站点列表
  List<String> get currentBusStops {
    if (serviceAreaIndex == 0) { // 选中Lagos
      return lagosBusstop;
    } else { // 选中Oyo
      return ibadanBusstop;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SingleChildScrollView(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            SizedBox(
              height: FraserDimensions.xFlexHeight(context, 24),
            ),

            GestureDetector(
              onTap: () {
                scrollController.dispose();
                scrollController = FixedExtentScrollController(initialItem: serviceAreaIndex);
                showCupertinoModalPopup(
                  context: context,
                  builder: (context) => CupertinoActionSheet(
                    actions: [
                      SizedBox(
                        height: FraserDimensions.xFlexHeight(context, 3),
                        child: CupertinoPicker(
                          scrollController: scrollController,
                          itemExtent: 64,
                          onSelectedItemChanged: (index) {
                            setState(() {
                              serviceAreaIndex = index;
                              // 切换区域时重置公交站点索引,避免越界
                              currentBusStopIndex = 0;
                            });
                          },
                          children: serviceAreas
                              .map((e) => Center(
                                    child: Text(
                                      e,
                                      style: FraserTextStyle.textBlack24,
                                    ),
                                  ))
                              .toList(),
                        ),
                      )
                    ],
                  ),
                );
              },
              child: Container(
                width: FraserDimensions.xFlexWidth(context, 1),
                height: FraserDimensions.xFlexHeight(context, 18),
                decoration: BoxDecoration(
                  color: FraserColors.line,
                  borderRadius: const BorderRadius.all(
                    Radius.circular(24),
                  ),
                ),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: [
                    Expanded(
                      child: Padding(
                        padding: const EdgeInsets.only(left: 24.0),
                        child: Text(
                          serviceAreas[serviceAreaIndex],
                          style: FraserTextStyle.textGrey16,
                        ),
                      ),
                    ),
                    Padding(
                      padding: const EdgeInsets.only(right: 16.0),
                      child: Icon(
                        Icons.arrow_drop_down_outlined,
                        color: FraserColors.primaryBlack,
                        size: 22,
                      ),
                    ),
                  ],
                ),
              ),
            ),
            SizedBox(
              height: FraserDimensions.xFlexHeight(context, 64),
            ),

            GestureDetector(
              onTap: () {
                scrollController.dispose();
                scrollController = FixedExtentScrollController(initialItem: currentBusStopIndex);
                showCupertinoModalPopup(
                  context: context,
                  builder: (context) => CupertinoActionSheet(
                    actions: [
                      SizedBox(
                        height: FraserDimensions.xFlexHeight(context, 3),
                        child: CupertinoPicker(
                          scrollController: scrollController,
                          itemExtent: 64,
                          onSelectedItemChanged: (index) {
                            setState(() {
                              currentBusStopIndex = index;
                            });
                          },
                          children: currentBusStops
                              .map((e) => Center(
                                    child: Text(
                                      e,
                                      style: FraserTextStyle.textBlack24,
                                    ),
                                  ))
                              .toList(),
                        ),
                      )
                    ],
                  ),
                );
              },
              child: Container(
                width: FraserDimensions.xFlexWidth(context, 1),
                height: FraserDimensions.xFlexHeight(context, 18),
                decoration: BoxDecoration(
                  color: FraserColors.line,
                  borderRadius: const BorderRadius.all(
                    Radius.circular(24),
                  ),
                ),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: [
                    Expanded(
                      child: Padding(
                        padding: const EdgeInsets.only(left: 24.0),
                        child: Text(
                          currentBusStops[currentBusStopIndex],
                          style: FraserTextStyle.textGrey16,
                        ),
                      ),
                    ),
                    Padding(
                      padding: const EdgeInsets.only(right: 16.0),
                      child: Icon(
                        Icons.arrow_drop_down_outlined,
                        color: FraserColors.primaryBlack,
                        size: 22,
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

关键改动说明:

  • 合并状态变量:移除ibadanIndex和lagosIndex,改用currentBusStopIndex统一管理当前选中的公交站点索引,减少冗余状态。
  • 动态获取站点列表:新增currentBusStops getter,根据当前选中的serviceAreaIndex自动返回对应城市的公交站点列表。
  • 切换区域重置索引:在第一个Picker的选择回调中,切换区域后将公交站点索引重置为0,避免因不同城市站点数量差异导致的索引越界问题。
  • 第二个Picker动态绑定:将第二个Picker的数据源、初始选中项、索引更新逻辑全部绑定到动态变量,实现区域与站点的联动效果。

内容的提问来源于stack exchange,提问作者Amen O. Olabode

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 05:35:23