diff --git a/packages/flutter/lib/src/material/stepper.dart b/packages/flutter/lib/src/material/stepper.dart index 32982fa232..17eec2e018 100644 --- a/packages/flutter/lib/src/material/stepper.dart +++ b/packages/flutter/lib/src/material/stepper.dart @@ -222,6 +222,7 @@ class Stepper extends StatefulWidget { this.stepIconHeight, this.stepIconWidth, this.stepIconMargin, + this.clipBehavior = Clip.none, }) : assert(0 <= currentStep && currentStep < steps.length), assert(stepIconHeight == null || (stepIconHeight >= _kStepSize && stepIconHeight <= _kMaxStepSize), 'stepIconHeight must be greater than $_kStepSize and less or equal to $_kMaxStepSize'), @@ -366,6 +367,15 @@ class Stepper extends StatefulWidget { /// Overrides the default step icon margin. final EdgeInsets? stepIconMargin; + /// The [Step.content] will be clipped to this Clip type. + /// + /// Defaults to [Clip.none]. + /// + /// See also: + /// + /// * [Clip], which explains how to use this property. + final Clip clipBehavior; + @override State createState() => _StepperState(); } @@ -795,7 +805,10 @@ class _StepperState extends State with TickerProviderStateMixin { ), child: Column( children: [ - widget.steps[index].content, + ClipRect( + clipBehavior: widget.clipBehavior, + child: widget.steps[index].content, + ), _buildVerticalControls(index), ], ), @@ -888,7 +901,10 @@ class _StepperState extends State with TickerProviderStateMixin { Visibility( maintainState: true, visible: i == widget.currentStep, - child: widget.steps[i].content, + child: ClipRect( + clipBehavior: widget.clipBehavior, + child: widget.steps[i].content, + ), ), ); } diff --git a/packages/flutter/test/material/stepper_test.dart b/packages/flutter/test/material/stepper_test.dart index 9c57d8e799..2ce124ff5f 100644 --- a/packages/flutter/test/material/stepper_test.dart +++ b/packages/flutter/test/material/stepper_test.dart @@ -1720,6 +1720,91 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async )); expect(lastConnector.width, equals(0.0)); }); + + // This is a regression test for https://github.com/flutter/flutter/issues/66007. + testWidgets('Default Stepper clipBehavior', (WidgetTester tester) async { + Widget buildStepper({ required StepperType type }) { + return MaterialApp( + home: Scaffold( + body: Center( + child: Stepper( + type: type, + steps: const [ + Step( + title: Text('step1'), + content: Text('step1 content'), + ), + Step( + title: Text('step2'), + content: Text('step2 content'), + ), + ], + ), + ), + ), + ); + } + + ClipRect getContentClipRect() { + return tester.widget(find.ancestor( + of: find.text('step1 content'), + matching: find.byType(ClipRect), + ).first); + } + + // Test vertical stepper with default clipBehavior. + await tester.pumpWidget(buildStepper(type: StepperType.vertical)); + + expect(getContentClipRect().clipBehavior, equals(Clip.none)); + + // Test horizontal stepper with default clipBehavior. + await tester.pumpWidget(buildStepper(type: StepperType.horizontal)); + + expect(getContentClipRect().clipBehavior, equals(Clip.none)); + }); + + // This is a regression test for https://github.com/flutter/flutter/issues/66007. + testWidgets('Stepper steps can be clipped', (WidgetTester tester) async { + Widget buildStepper({ required StepperType type, required Clip clipBehavior }) { + return MaterialApp( + home: Scaffold( + body: Center( + child: Stepper( + clipBehavior: clipBehavior, + type: type, + steps: const [ + Step( + title: Text('step1'), + content: Text('step1 content'), + ), + Step( + title: Text('step2'), + content: Text('step2 content'), + ), + ], + ), + ), + ), + ); + } + + ClipRect getContentClipRect() { + return tester.widget(find.ancestor( + of: find.text('step1 content'), + matching: find.byType(ClipRect), + ).first); + } + + // Test vertical stepper with clipBehavior set to Clip.hardEdge. + await tester.pumpWidget(buildStepper(type: StepperType.vertical, clipBehavior: Clip.hardEdge)); + + expect(getContentClipRect().clipBehavior, equals(Clip.hardEdge)); + + // Test horizontal stepper with clipBehavior set to Clip.hardEdge. + await tester.pumpWidget(buildStepper(type: StepperType.horizontal, clipBehavior: Clip.hardEdge)); + + expect(getContentClipRect().clipBehavior, equals(Clip.hardEdge)); + }); } class _TappableColorWidget extends StatefulWidget {