Repository navigation
[material_ui] Fix GridTile crash when the incoming constraints are unbounded #12586
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
f920011
0f9454f
6ddc5c0
0f5a19a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -5,6 +5,7 @@ | |||||||||||
| /// @docImport 'grid_tile_bar.dart'; | ||||||||||||
| library; | ||||||||||||
|
|
||||||||||||
| import 'package:flutter/rendering.dart'; | ||||||||||||
| import 'package:flutter/widgets.dart'; | ||||||||||||
|
|
||||||||||||
| /// A tile in a Material Design grid list. | ||||||||||||
|
|
@@ -46,12 +47,77 @@ class GridTile extends StatelessWidget { | |||||||||||
| return child; | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| // The child is not positioned so that the Stack can size itself to it | ||||||||||||
| // along an unbounded axis (e.g. in a horizontally scrolling ListView), | ||||||||||||
| // where a Stack of only positioned children would try to be infinitely | ||||||||||||
| // large. Along bounded axes, the child still fills the available space. | ||||||||||||
| return Stack( | ||||||||||||
| fit: StackFit.passthrough, | ||||||||||||
| children: <Widget>[ | ||||||||||||
| Positioned.fill(child: child), | ||||||||||||
| _FillBoundedAxes(child: child), | ||||||||||||
| if (header != null) Positioned(top: 0.0, left: 0.0, right: 0.0, child: header!), | ||||||||||||
| if (footer != null) Positioned(left: 0.0, bottom: 0.0, right: 0.0, child: footer!), | ||||||||||||
| ], | ||||||||||||
| ); | ||||||||||||
| } | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| /// Makes its child as big as the incoming constraints allow along every | ||||||||||||
| /// bounded axis, and lets the child pick its own size along unbounded axes. | ||||||||||||
| class _FillBoundedAxes extends SingleChildRenderObjectWidget { | ||||||||||||
| const _FillBoundedAxes({required Widget super.child}); | ||||||||||||
|
|
||||||||||||
| @override | ||||||||||||
| _RenderFillBoundedAxes createRenderObject(BuildContext context) => _RenderFillBoundedAxes(); | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| class _RenderFillBoundedAxes extends RenderProxyBox { | ||||||||||||
| static BoxConstraints _fillBoundedAxes(BoxConstraints constraints) { | ||||||||||||
| return constraints.copyWith( | ||||||||||||
| minWidth: constraints.hasBoundedWidth ? constraints.maxWidth : constraints.minWidth, | ||||||||||||
| minHeight: constraints.hasBoundedHeight ? constraints.maxHeight : constraints.minHeight, | ||||||||||||
| ); | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| // The tile used to report zero intrinsic sizes because its child was | ||||||||||||
| // positioned, which the Stack ignores for intrinsics. Keep doing so. | ||||||||||||
| @override | ||||||||||||
| double computeMinIntrinsicWidth(double height) => 0.0; | ||||||||||||
|
|
||||||||||||
| @override | ||||||||||||
| double computeMaxIntrinsicWidth(double height) => 0.0; | ||||||||||||
|
|
||||||||||||
| @override | ||||||||||||
| double computeMinIntrinsicHeight(double width) => 0.0; | ||||||||||||
|
|
||||||||||||
| @override | ||||||||||||
| double computeMaxIntrinsicHeight(double width) => 0.0; | ||||||||||||
|
|
||||||||||||
| @override | ||||||||||||
|
kaluli123123 marked this conversation as resolved.
Resolved
|
||||||||||||
| Size computeDryLayout(BoxConstraints constraints) { | ||||||||||||
| final BoxConstraints childConstraints = _fillBoundedAxes(constraints); | ||||||||||||
| if (childConstraints.isTight) { | ||||||||||||
| return childConstraints.smallest; | ||||||||||||
| } | ||||||||||||
| return constraints.constrain( | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in 0f5a19a. Added a regression with a Verification with Flutter 3.47.0 / Dart 3.13:
These are local results; current-head CI and maintainer review remain separate gates. |
||||||||||||
| child?.getDryLayout(childConstraints) ?? childConstraints.smallest, | ||||||||||||
| ); | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| @override | ||||||||||||
| double? computeDryBaseline(BoxConstraints constraints, TextBaseline baseline) { | ||||||||||||
| return child?.getDryBaseline(_fillBoundedAxes(constraints), baseline); | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| @override | ||||||||||||
| void performLayout() { | ||||||||||||
| final BoxConstraints childConstraints = _fillBoundedAxes(constraints); | ||||||||||||
| final RenderBox? child = this.child; | ||||||||||||
| if (child == null) { | ||||||||||||
| size = constraints.constrain(childConstraints.smallest); | ||||||||||||
| return; | ||||||||||||
| } | ||||||||||||
| child.layout(childConstraints, parentUsesSize: true); | ||||||||||||
| size = constraints.constrain(child.size); | ||||||||||||
| } | ||||||||||||
| } | ||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| changelog: | | ||
| - Fix `GridTile` crash when the incoming constraints are unbounded (e.g. inside a horizontally scrolling `ListView`). | ||
| version: patch |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since reporting zero intrinsics is deliberate it would be nice to have a small test for it so a future refactor doesn't change it by accident.