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

如何在Flutter中创建超过20步的优化显示Stepper组件

解决Flutter横向Stepper多步骤布局混乱的问题

原生Stepper(type: StepperType.horizontal)在步骤数量较多时,会将所有步骤平均分配宽度,导致每个步骤的空间被过度压缩,出现文字重叠、布局变形的问题。以下是两种可行的解决思路:

方案一:给原生Stepper添加横向滚动支持

通过SingleChildScrollView包裹Stepper,让步骤区域可以横向滚动,同时设置合适的容器宽度保证每个步骤有足够显示空间:

@override
Widget build(BuildContext context) {
  final steps = stepList();
  return Scaffold(
    appBar: AppBar(
      centerTitle: true,
      backgroundColor: Colors.green,
      title: const Text('test', style: TextStyle(color: Colors.white)),
    ),
    body: SingleChildScrollView(
      scrollDirection: Axis.horizontal,
      child: SizedBox(
        // 按每个步骤占屏幕1/3宽度计算总宽度,可根据需求调整比例
        width: MediaQuery.of(context).size.width * (steps.length / 3),
        child: Stepper(
          type: StepperType.horizontal,
          steps: steps,
          currentStep: 0, // 控制当前选中步骤
        ),
      ),
    ),
  );
}

这种方式优点是改动小,保留原生Stepper的所有交互逻辑,适合快速解决问题。

方案二:自定义可滚动步进器组件

如果需要更贴合设计需求的样式(比如紧凑的步骤指示器、自定义状态样式),可以完全自定义一个可滚动的步进器:

class ScrollableStepper extends StatelessWidget {
  final List<String> stepTitles;
  final int currentStep;
  final ValueChanged<int>? onStepTap;

  const ScrollableStepper({
    super.key,
    required this.stepTitles,
    required this.currentStep,
    this.onStepTap,
  });

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      scrollDirection: Axis.horizontal,
      padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20),
      child: Row(
        children: List.generate(stepTitles.length, (index) {
          final isActive = index == currentStep;
          final isCompleted = index < currentStep;
          return GestureDetector(
            onTap: onStepTap != null ? () => onStepTap!(index) : null,
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                // 步骤指示器
                Container(
                  width: 32,
                  height: 32,
                  decoration: BoxDecoration(
                    color: isActive 
                        ? Colors.deepPurple 
                        : isCompleted 
                            ? Colors.green 
                            : Colors.grey.shade300,
                    borderRadius: BorderRadius.circular(16),
                  ),
                  child: Center(
                    child: Text(
                      isCompleted ? '✓' : '${index + 1}',
                      style: const TextStyle(
                        color: Colors.white,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  ),
                ),
                const SizedBox(height: 4),
                // 步骤标题
                SizedBox(
                  width: 60,
                  child: Text(
                    stepTitles[index],
                    textAlign: TextAlign.center,
                    style: TextStyle(
                      fontSize: 12,
                      color: isActive ? Colors.deepPurple : Colors.grey,
                    ),
                  ),
                ),
                // 步骤间连接线
                if (index < stepTitles.length - 1)
                  Container(
                    width: 40,
                    height: 2,
                    color: index < currentStep ? Colors.green : Colors.grey.shade300,
                  ),
              ],
            ),
          );
        }),
      ),
    );
  }
}

使用方式示例:

@override
Widget build(BuildContext context) {
  final stepTitles = List.generate(20, (i) => 'Step ${i+1}');
  return Scaffold(
    appBar: AppBar(
      centerTitle: true,
      backgroundColor: Colors.green,
      title: const Text('test', style: TextStyle(color: Colors.white)),
    ),
    body: Column(
      children: [
        ScrollableStepper(
          stepTitles: stepTitles,
          currentStep: 0,
          onStepTap: (index) {
            // 处理步骤切换逻辑
          },
        ),
        const Expanded(
          child: Center(child: Text('当前步骤内容区域')),
        ),
      ],
    ),
  );
}

自定义组件的优势在于可以完全控制UI样式,比如调整指示器大小、颜色、连接线样式,更易匹配设计稿需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 02:33:12