Flutter的步骤条超出可视区域

移动开发 2026-07-09

我是Flutter新手,在使用Stepper小部件时遇到了一个问题:当我跳转到某一步时,该步骤会被滚动到可视区域,这没问题,但当Stepper将旧步骤折叠、展开新步骤时,如果你选择当前步骤之后的某个步骤,它会展开到超出可视区域的位置。

我做了一个可以在 DartPad 上运行的小示例(当前使用Dart 3.11.5、Flutter 3.41.9):

import 'package:flutter/material.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomeScreen()
    );
  }
}

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  var _selected = 0;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Home')),
      body: Stepper(
        currentStep: _selected,
        onStepTapped: (step) async {
          // Uncomment this line to see the step expanding out of viewing area after a delay
          // await Future.delayed(const Duration(milliseconds: 300));
          setState(() { _selected = step; });
        },
        steps: List<Step>.generate(50, (i) => Step(title: Text('Step $i'), content: Text('Hi')))
      )
    );
  }
}

要复现这个问题,只需在尚未滚动到屏幕尽头的情况下,选择当前步骤之后的任意一个步骤。

我也录制了一个视频:https://youtu.be/-yZDXAoGIQY

有什么办法可以解决吗?

解决方案

这是设计中的行为。如果你查看 Stepper 的内部实现,你会注意到,当一个步骤被点击时,控件会先滚动到所点击的步骤,随后才调用 onStepTapped 函数。相关的代码看起来是这样的:

InkWell(
  onTap: widget.steps[i].state != StepState.disabled
      ? () {
          // In the vertical case we need to scroll to the newly tapped step.
          Scrollable.ensureVisible(
            _keys[i].currentContext!,
            curve: Curves.fastOutSlowIn,
            duration: kThemeAnimationDuration,
          );

          widget.onStepTapped?.call(i);
        }
      : null,
  canRequestFocus: widget.steps[i].state != StepState.disabled,
  child: _buildVerticalHeader(i),
),

由于这种执行顺序,通常在你想处理步骤推进逻辑时,最好依赖 onStepContinue 回调,而不是只依赖 onStepTapped

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章