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

如何在Flutter中实现截图所示的自定义Stepper?求代码及解析

Flutter 自定义横向步进器UI实现

一、开发清晰指引

  • 拆解UI结构:该步进器为横向排列的多步骤指示器,每个步骤包含「圆形状态指示器」「步骤标题」「状态标签」,步骤间通过动态样式的连接线关联
  • 组件拆分策略:封装独立的StepItem逻辑负责单个步骤的渲染,父组件统一管理全局步骤状态与布局
  • 状态控制逻辑:通过当前步骤索引,为每个步骤分配「已完成」「当前进行中」「未开始」三种状态,对应不同的样式表现
  • 适配处理:使用Expanded让每个步骤均分宽度,确保在不同屏幕尺寸下的布局一致性

二、完整自定义实现代码

import 'package:flutter/material.dart';

void main() => runApp(const StepperDemoApp());

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('自定义步进器示例')),
        body: const Padding(
          padding: EdgeInsets.all(20.0),
          child: CustomHorizontalStepper(
            currentStep: 1,
            steps: [
              StepData(title: '订单确认', status: '已完成'),
              StepData(title: '支付成功', status: '处理中'),
              StepData(title: '发货准备', status: '未开始'),
              StepData(title: '已送达', status: '未开始'),
            ],
          ),
        ),
      ),
    );
  }
}

// 步骤数据模型
class StepData {
  final String title;
  final String status;

  StepData({required this.title, required this.status});
}

class CustomHorizontalStepper extends StatefulWidget {
  final int currentStep;
  final List<StepData> steps;

  const CustomHorizontalStepper({
    super.key,
    required this.currentStep,
    required this.steps,
  });

  @override
  State<CustomHorizontalStepper> createState() => _CustomHorizontalStepperState();
}

class _CustomHorizontalStepperState extends State<CustomHorizontalStepper> {
  @override
  Widget build(BuildContext context) {
    return Row(
      children: List.generate(widget.steps.length, (index) {
        final isCompleted = index < widget.currentStep;
        final isCurrent = index == widget.currentStep;
        final isUnStarted = index > widget.currentStep;

        return Expanded(
          child: Column(
            children: [
              // 步骤指示器与连接线
              Row(
                children: [
                  // 圆形状态指示器
                  Container(
                    width: 32,
                    height: 32,
                    decoration: BoxDecoration(
                      color: isCompleted
                          ? Colors.green
                          : isCurrent
                              ? Colors.blue
                              : Colors.grey.shade300,
                      borderRadius: BorderRadius.circular(16),
                    ),
                    child: Center(
                      child: isCompleted
                          ? const Icon(Icons.check, color: Colors.white, size: 18)
                          : isCurrent
                              ? const Icon(Icons.circle, color: Colors.white, size: 12)
                              : Text(
                                  '${index + 1}',
                                  style: TextStyle(
                                    color: isUnStarted ? Colors.grey : Colors.white,
                                    fontSize: 14,
                                    fontWeight: FontWeight.bold,
                                  ),
                                ),
                    ),
                  ),
                  // 步骤间连接线(最后一个步骤不显示)
                  if (index != widget.steps.length - 1)
                    Expanded(
                      child: Container(
                        height: 2,
                        color: index < widget.currentStep ? Colors.green : Colors.grey.shade300,
                      ),
                    ),
                ],
              ),
              const SizedBox(height: 8),
              // 步骤标题
              Text(
                widget.steps[index].title,
                style: TextStyle(
                  fontSize: 13,
                  fontWeight: FontWeight.w500,
                  color: isCompleted || isCurrent ? Colors.black87 : Colors.grey,
                ),
                textAlign: TextAlign.center,
              ),
              const SizedBox(height: 4),
              // 状态标签
              Text(
                widget.steps[index].status,
                style: TextStyle(
                  fontSize: 11,
                  color: isCompleted
                      ? Colors.green
                      : isCurrent
                          ? Colors.blue
                          : Colors.grey,
                ),
                textAlign: TextAlign.center,
              ),
            ],
          ),
        );
      }),
    );
  }
}

三、详细设计解析

  1. 状态样式控制

    • 通过currentStep索引判断每个步骤的状态:index < currentStep为已完成(绿色背景+对勾图标),index == currentStep为当前步骤(蓝色背景+空心圆图标),index > currentStep为未开始(灰色背景+步骤数字)
    • 连接线颜色随步骤状态动态变化,已完成区间显示绿色,未完成区间显示灰色
  2. 布局逻辑

    • 使用Row+Expanded实现横向均分布局,每个步骤占据相等宽度,适配不同屏幕尺寸
    • 单个步骤采用Column垂直排列指示器、标题、状态标签,保证视觉层级清晰
  3. 可扩展性设计

    • 封装StepData数据模型,支持自定义每个步骤的标题与状态文本
    • 可通过扩展参数添加点击交互(如点击步骤切换当前索引)、自定义颜色主题等功能
  4. 视觉细节优化

    • 统一设置间距(SizedBox)保证元素间留白合理
    • 状态标签使用对应状态的颜色,强化视觉反馈
    • 指示器的尺寸、圆角保持一致,保证UI统一性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 10:28:17