Fix Stepper connector not being properly displayed (#160193)

@ayyoub-coder gave a fantastic summary of the problem in #160177: if a
`Container` doesn't have a child or unbounded constraints, it will
expand to fill its parent, whereas a `ColoredBox` defaults to zero size.

I also noticed that in the main branch, the `PositionedDirectional`
widget has an unused `width` parameter, and instead builds a `SizedBox`
child for it.

This pull request cleans up the `Stepper` subtree a bit and allows the
connector to display properly.

fixes #160156
This commit is contained in:
Nate Wilson 2024-12-13 09:26:26 -07:00 committed by GitHub
parent 335300d9da
commit 7aa4d2d3ec
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 81 additions and 8 deletions

View File

@ -784,21 +784,20 @@ class _StepperState extends State<Stepper> with TickerProviderStateMixin {
start: 24.0 + (additionalMarginLeft ?? 0.0) + (additionalMarginRight ?? 0.0),
top: 0.0,
bottom: 0.0,
child: SizedBox(
width: _stepIconWidth ?? _kStepSize,
child: Center(
// The line is drawn from the center of the circle vertically until
// it reaches the bottom and then horizontally to the edge of the
// stepper.
width: _stepIconWidth ?? _kStepSize,
child: Center(
child: SizedBox(
width: !_isLast(index) ? (widget.connectorThickness ?? 1.0) : 0.0,
child: ColoredBox(color: _connectorColor(widget.steps[index].isActive)),
),
child: SizedBox(
width: !_isLast(index) ? (widget.connectorThickness ?? 1.0) : 0.0,
height: double.infinity,
child: ColoredBox(color: _connectorColor(widget.steps[index].isActive)),
),
),
),
AnimatedCrossFade(
firstChild: const SizedBox(height: 0),
firstChild: const SizedBox(width: double.infinity, height: 0),
secondChild: Padding(
padding: EdgeInsetsDirectional.only(
// Adjust [controlsBuilder] padding so that the content is

View File

@ -1815,6 +1815,80 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async
expect(getContentClipRect().clipBehavior, equals(Clip.hardEdge));
});
// Regression test for https://github.com/flutter/flutter/issues/160156.
testWidgets('Vertical stepper border displays correctly', (WidgetTester tester) async {
int index = 0;
const Color connectorColor = Color(0xff00ffff);
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: Center(
child: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Stepper(
currentStep: index,
connectorColor: const WidgetStatePropertyAll<Color>(connectorColor),
onStepTapped: (int value) {
setState(() {
index = value;
});
},
steps: const <Step>[
Step(
title: Text('step1'),
content: Text('step1 content'),
),
Step(
title: Text('step2'),
content: Text('step2 content'),
),
],
);
}
),
),
),
),
);
final Finder findConnector = find.descendant(
of: find.byType(Stepper),
matching: find.descendant(
of: find.byType(PositionedDirectional),
matching: find.byElementPredicate((BuildContext context) {
if (context case BuildContext(
widget: ColoredBox(color: connectorColor),
size: Size(width: 1.0, height: > 0),
)) {
return true;
}
return false;
}),
),
);
void verifyConnector() {
expect(findConnector, findsOneWidget);
final RenderBox renderBox = tester.renderObject(findConnector);
expect(renderBox, paints..rect(color: connectorColor));
}
verifyConnector();
final Finder findStep2 = find.text('step2');
await tester.tap(findStep2);
const int checkCount = 5;
final Duration duration = Duration(
microseconds: kThemeAnimationDuration.inMicroseconds ~/ (checkCount + 1),
);
for (int i = 0; i < checkCount; i++) {
await tester.pump(duration);
verifyConnector();
}
});
}
class _TappableColorWidget extends StatefulWidget {