Implement computeDryBaseline for RenderChip (#146224)

Also, use `getDryLayout` for the first pass of the `label` layout.  

The computeDryBaseline stuff doesn't have a test because there're asserts making sure it returns the same result as `computeDistanceToActualBaseline`. I have tried adding `+1` to the return expression and `flutter test` fails.
This commit is contained in:
LongCatIsLooong 2024-05-08 08:27:59 +08:00 committed by GitHub
parent 4abd7352f8
commit e37b29daa9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 55 additions and 27 deletions

View File

@ -1728,9 +1728,6 @@ class _RenderChip extends RenderBox with SlottedContainerRenderObjectMixin<_Chip
bool get isDrawingCheckmark => theme.showCheckmark && !checkmarkAnimation.isDismissed;
bool get deleteIconShowing => !deleteDrawerAnimation.isDismissed;
@override
bool get sizedByParent => false;
static Rect _boxRect(RenderBox box) => _boxParentData(box).offset & box.size;
static BoxParentData _boxParentData(RenderBox box) => box.parentData! as BoxParentData;
@ -1775,29 +1772,22 @@ class _RenderChip extends RenderBox with SlottedContainerRenderObjectMixin<_Chip
return (BaselineOffset(label.getDistanceToActualBaseline(baseline)) + _boxParentData(label).offset.dy).offset;
}
Size _layoutLabel(BoxConstraints contentConstraints, double iconSizes, Size size, Size rawSize, [ChildLayouter layoutChild = ChildLayoutHelper.layoutChild]) {
BoxConstraints _labelConstraintsFrom(BoxConstraints contentConstraints, double iconWidth, double contentSize, Size rawLabelSize) {
// Now that we know the label height and the width of the icons, we can
// determine how much to shrink the width constraints for the "real" layout.
final double maxLabelWidth = contentConstraints.maxWidth.isFinite
? math.max(
0.0,
contentConstraints.maxWidth - iconSizes - theme.labelPadding.horizontal - theme.padding.horizontal,
)
: size.width;
final BoxConstraints labelConstraints = BoxConstraints(
minHeight: rawSize.height,
maxHeight: size.height,
maxWidth: maxLabelWidth,
final double freeSpace = contentConstraints.maxWidth - iconWidth - theme.labelPadding.horizontal - theme.padding.horizontal;
final double maxLabelWidth = math.max(0.0, freeSpace);
return BoxConstraints(
minHeight: rawLabelSize.height,
maxHeight: contentSize,
maxWidth: maxLabelWidth.isFinite ? maxLabelWidth : rawLabelSize.width,
);
final Size updatedSize = layoutChild(label, labelConstraints);
return theme.labelPadding.inflateSize(updatedSize);
}
Size _layoutAvatar(double contentSize, [ChildLayouter layoutChild = ChildLayoutHelper.layoutChild]) {
final double requestedSize = math.max(0.0, contentSize);
final BoxConstraints avatarConstraints = avatarBoxConstraints ?? BoxConstraints.tightFor(
width: requestedSize,
height: requestedSize,
width: contentSize,
height: contentSize,
);
final Size avatarBoxSize = layoutChild(avatar, avatarConstraints);
if (!theme.showCheckmark && !theme.showAvatar) {
@ -1808,10 +1798,9 @@ class _RenderChip extends RenderBox with SlottedContainerRenderObjectMixin<_Chip
}
Size _layoutDeleteIcon(double contentSize, [ChildLayouter layoutChild = ChildLayoutHelper.layoutChild]) {
final double requestedSize = math.max(0.0, contentSize);
final BoxConstraints deleteIconConstraints = deleteIconBoxConstraints ?? BoxConstraints.tightFor(
width: requestedSize,
height: requestedSize,
width: contentSize,
height: contentSize,
);
final Size boxSize = layoutChild(deleteIcon, deleteIconConstraints);
if (!deleteIconShowing) {
@ -1851,25 +1840,36 @@ class _RenderChip extends RenderBox with SlottedContainerRenderObjectMixin<_Chip
return _computeSizes(constraints, ChildLayoutHelper.dryLayoutChild).size;
}
@override
double? computeDryBaseline(BoxConstraints constraints, TextBaseline baseline) {
final _ChipSizes sizes = _computeSizes(constraints, ChildLayoutHelper.dryLayoutChild);
final BaselineOffset labelBaseline = BaselineOffset(label.getDryBaseline(sizes.labelConstraints, baseline))
+ (sizes.content - sizes.label.height + sizes.densityAdjustment.dy) / 2
+ theme.padding.top + theme.labelPadding.top;
return labelBaseline.offset;
}
_ChipSizes _computeSizes(BoxConstraints constraints, ChildLayouter layoutChild) {
final BoxConstraints contentConstraints = constraints.loosen();
// Find out the height of the label within the constraints.
final Offset densityAdjustment = Offset(0.0, theme.visualDensity.baseSizeAdjustment.dy / 2.0);
final Size rawLabelSize = layoutChild(label, contentConstraints);
final Size rawLabelSize = label.getDryLayout(contentConstraints);
final double contentSize = math.max(
_kChipHeight - theme.padding.vertical + theme.labelPadding.vertical,
rawLabelSize.height + theme.labelPadding.vertical,
);
assert(contentSize >= rawLabelSize.height);
final Size avatarSize = _layoutAvatar(contentSize, layoutChild);
final Size deleteIconSize = _layoutDeleteIcon(contentSize, layoutChild);
final Size labelSize = _layoutLabel(
final BoxConstraints labelConstraints = _labelConstraintsFrom(
contentConstraints,
avatarSize.width + deleteIconSize.width,
Size(rawLabelSize.width, contentSize),
contentSize,
rawLabelSize,
layoutChild,
);
final Size labelSize = theme.labelPadding.inflateSize(layoutChild(label, labelConstraints));
final Offset densityAdjustment = Offset(0.0, theme.visualDensity.baseSizeAdjustment.dy / 2.0);
// This is the overall size of the content: it doesn't include
// theme.padding, that is added in at the end.
final Size overallSize = Size(
@ -1887,6 +1887,7 @@ class _RenderChip extends RenderBox with SlottedContainerRenderObjectMixin<_Chip
content: contentSize,
densityAdjustment: densityAdjustment,
avatar: avatarSize,
labelConstraints: labelConstraints,
label: labelSize,
deleteIcon: deleteIconSize,
);
@ -2232,6 +2233,7 @@ class _ChipSizes {
required this.overall,
required this.content,
required this.avatar,
required this.labelConstraints,
required this.label,
required this.deleteIcon,
required this.densityAdjustment,
@ -2240,6 +2242,7 @@ class _ChipSizes {
final Size overall;
final double content;
final Size avatar;
final BoxConstraints labelConstraints;
final Size label;
final Size deleteIcon;
final Offset densityAdjustment;

View File

@ -5781,6 +5781,18 @@ void main() {
// Test rendered icon color.
expect(getIconStyle(tester, deleteIcon)?.color, deleteIconColor);
});
testWidgets('Chip label only does layout once', (WidgetTester tester) async {
final RenderLayoutCount renderLayoutCount = RenderLayoutCount();
final Widget layoutCounter = Center(
key: GlobalKey(),
child: WidgetToRenderBoxAdapter(renderBox: renderLayoutCount),
);
await tester.pumpWidget(wrapForChip(child: RawChip(label: layoutCounter)));
expect(renderLayoutCount.layoutCount, 1);
});
}
class _MaterialStateOutlinedBorder extends StadiumBorder implements MaterialStateOutlinedBorder {
@ -5800,3 +5812,16 @@ class _MaterialStateBorderSide extends MaterialStateBorderSide {
@override
BorderSide? resolve(Set<MaterialState> states) => resolver(states);
}
class RenderLayoutCount extends RenderBox {
int layoutCount = 0;
@override
Size computeDryLayout(covariant BoxConstraints constraints) => constraints.biggest;
@override
void performLayout() {
layoutCount += 1;
size = constraints.biggest;
}
}