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

Flutter垂直Stepper布局调整:内容居左,步骤指示线居右

解决Flutter垂直Stepper内容与指示线位置互换问题

我使用Flutter的Stepper组件时,垂直视图模式下内容默认显示在步骤指示线右侧,需要调整为内容在左侧、步骤指示线在右侧的布局。

原示例代码

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyStepper(),
    );
  }
}

class MyStepper extends StatefulWidget {
  @override
  _MyStepperState createState() => _MyStepperState();
}

class _MyStepperState extends State<MyStepper> {
  int _currentStep = 0;

  List<Step> steps = [
    Step(
      title: Text('Step 1'),
      content: Column(
        children: [
          TextField(
            controller:TextEditingController(),
            decoration: InputDecoration(labelText: 'Username'),
          ),
          TextField(
            controller: TextEditingController(),
            decoration: InputDecoration(labelText: 'Password'),
            obscureText: true,
          ),
        ],
      ),
      isActive: true,
    ),
    Step(
      title: Text('Step 2'),
      content: Text('This is the content of Step 2'),
      isActive: false,
    ),
    Step(
      title: Text('Step 3'),
      content: Text('This is the content of Step 3'),
      isActive: false,
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Stepper Example'),
      ),
      body: Stepper(
        currentStep: _currentStep,
        onStepContinue: () {
          setState(() {
            if (_currentStep < steps.length - 1) {
              _currentStep += 1;
            }
          });
        },
        onStepCancel: () {
          setState(() {
            if (_currentStep > 0) {
              _currentStep -= 1;
            }
          });
        },
        steps: steps,
      ),
    );
  }
}

解决方案

Flutter默认Stepper没有直接配置项调整垂直模式下的布局方向,可通过以下两种方式实现需求:

方法一:利用Directionality反转布局并修正文本方向

通过Directionality将Stepper的布局方向设为从右到左(rtl),再将内容区域的文本方向还原为从左到右(ltr),实现指示线与内容的位置互换:

修改build方法中的Stepper部分:

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text('Flutter Stepper Example'),
    ),
    body: Directionality(
      textDirection: TextDirection.rtl,
      child: Stepper(
        currentStep: _currentStep,
        onStepContinue: () {
          setState(() {
            if (_currentStep < steps.length - 1) {
              _currentStep += 1;
            }
          });
        },
        onStepCancel: () {
          setState(() {
            if (_currentStep > 0) {
              _currentStep -= 1;
            }
          });
        },
        steps: steps.map((step) {
          return Step(
            title: Directionality(
              textDirection: TextDirection.ltr,
              child: step.title,
            ),
            content: Directionality(
              textDirection: TextDirection.ltr,
              child: step.content,
            ),
            isActive: step.isActive,
            state: step.state,
          );
        }).toList(),
      ),
    ),
  );
}

方法二:自定义Step布局(更灵活可控)

通过Stepper的stepBuilder属性完全自定义每个Step的UI结构,将指示器放在右侧、内容放在左侧:

修改build方法中的Stepper部分:

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text('Flutter Stepper Example'),
    ),
    body: Stepper(
      currentStep: _currentStep,
      onStepContinue: () {
        setState(() {
          if (_currentStep < steps.length - 1) {
            _currentStep += 1;
          }
        });
      },
      onStepCancel: () {
        setState(() {
          if (_currentStep > 0) {
            _currentStep -= 1;
          }
        });
      },
      stepBuilder: (context, stepIndex) {
        final step = steps[stepIndex];
        return Column(
          children: [
            Row(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                // 内容区域(左侧)
                Expanded(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      step.title,
                      SizedBox(height: 8),
                      step.content,
                    ],
                  ),
                ),
                // 指示器区域(右侧)
                Container(
                  margin: EdgeInsets.symmetric(horizontal: 16),
                  child: StepIcon(
                    state: step.state ?? (_currentStep == stepIndex ? StepState.indexed : StepState.disabled),
                    isActive: step.isActive,
                    icon: Text('${stepIndex + 1}'),
                  ),
                ),
              ],
            ),
            // 步骤分隔线
            if (stepIndex != steps.length - 1)
              Container(
                height: 48,
                width: 2,
                color: Colors.grey.shade300,
                margin: EdgeInsets.only(left: MediaQuery.of(context).size.width - 48),
              ),
          ],
        );
      },
    ),
  );
}

说明

  • 方法一实现简单,适合快速调整布局,但需注意文本方向的还原,避免输入框、文本显示异常。
  • 方法二自定义程度更高,可灵活调整指示器、内容的样式和间距,适合有定制化UI需求的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 22:00:17