Allow IconButton to have smaller sizes (#47457)
This commit is contained in:
parent
5d37de2685
commit
c88320458e
@ -366,10 +366,7 @@ class _RawMaterialButtonState extends State<RawMaterialButton> {
|
||||
final Color effectiveTextColor = MaterialStateProperty.resolveAs<Color>(widget.textStyle?.color, _states);
|
||||
final ShapeBorder effectiveShape = MaterialStateProperty.resolveAs<ShapeBorder>(widget.shape, _states);
|
||||
final Offset densityAdjustment = widget.visualDensity.baseSizeAdjustment;
|
||||
final BoxConstraints effectiveConstraints = widget.constraints.copyWith(
|
||||
minWidth: widget.constraints.minWidth != null ? (widget.constraints.minWidth + densityAdjustment.dx).clamp(0.0, double.infinity) as double : null,
|
||||
minHeight: widget.constraints.minWidth != null ? (widget.constraints.minHeight + densityAdjustment.dy).clamp(0.0, double.infinity) as double : null,
|
||||
);
|
||||
final BoxConstraints effectiveConstraints = widget.visualDensity.effectiveConstraints(widget.constraints);
|
||||
final EdgeInsetsGeometry padding = widget.padding.add(
|
||||
EdgeInsets.only(
|
||||
left: densityAdjustment.dx,
|
||||
|
@ -154,6 +154,7 @@ class IconButton extends StatelessWidget {
|
||||
this.autofocus = false,
|
||||
this.tooltip,
|
||||
this.enableFeedback = true,
|
||||
this.constraints,
|
||||
}) : assert(iconSize != null),
|
||||
assert(padding != null),
|
||||
assert(alignment != null),
|
||||
@ -288,6 +289,26 @@ class IconButton extends StatelessWidget {
|
||||
/// * [Feedback] for providing platform-specific feedback to certain actions.
|
||||
final bool enableFeedback;
|
||||
|
||||
/// Optional size constraints for the button.
|
||||
///
|
||||
/// When unspecified, defaults to:
|
||||
/// ```dart
|
||||
/// const BoxConstraints(
|
||||
/// minWidth: kMinInteractiveDimension,
|
||||
/// minHeight: kMinInteractiveDimension,
|
||||
/// )
|
||||
/// ```
|
||||
/// where [kMinInteractiveDimension] is 48.0, and then with visual density
|
||||
/// applied.
|
||||
///
|
||||
/// The default constraints ensure that the button is accessible.
|
||||
/// Specifying this parameter enables creation of buttons smaller than
|
||||
/// the minimum size, but it is not recommended.
|
||||
///
|
||||
/// The visual density uses the [visualDensity] parameter if specified,
|
||||
/// and `Theme.of(context).visualDensity` otherwise.
|
||||
final BoxConstraints constraints;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
assert(debugCheckHasMaterial(context));
|
||||
@ -298,9 +319,16 @@ class IconButton extends StatelessWidget {
|
||||
else
|
||||
currentColor = disabledColor ?? theme.disabledColor;
|
||||
|
||||
final Offset densityAdjustment = (visualDensity ?? theme.visualDensity).baseSizeAdjustment;
|
||||
final VisualDensity effectiveVisualDensity = visualDensity ?? theme.visualDensity;
|
||||
|
||||
final BoxConstraints unadjustedConstraints = constraints ?? const BoxConstraints(
|
||||
minWidth: _kMinButtonSize,
|
||||
minHeight: _kMinButtonSize,
|
||||
);
|
||||
final BoxConstraints adjustedConstraints = effectiveVisualDensity.effectiveConstraints(unadjustedConstraints);
|
||||
|
||||
Widget result = ConstrainedBox(
|
||||
constraints: BoxConstraints(minWidth: _kMinButtonSize + densityAdjustment.dx, minHeight: _kMinButtonSize + densityAdjustment.dy),
|
||||
constraints: adjustedConstraints,
|
||||
child: Padding(
|
||||
padding: padding,
|
||||
child: SizedBox(
|
||||
|
@ -1815,6 +1815,16 @@ class VisualDensity extends Diagnosticable {
|
||||
);
|
||||
}
|
||||
|
||||
/// Return a copy of [constraints] whose minimum width and height have been
|
||||
/// updated with the [baseSizeAdjustment].
|
||||
BoxConstraints effectiveConstraints(BoxConstraints constraints){
|
||||
assert(constraints != null && constraints.debugAssertIsValid());
|
||||
return constraints.copyWith(
|
||||
minWidth: (constraints.minWidth + baseSizeAdjustment.dx).clamp(0.0, double.infinity).toDouble(),
|
||||
minHeight: (constraints.minHeight + baseSizeAdjustment.dy).clamp(0.0, double.infinity).toDouble(),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (other.runtimeType != runtimeType) {
|
||||
|
@ -75,6 +75,69 @@ void main() {
|
||||
expect(iconButton.size, const Size(70.0, 70.0));
|
||||
});
|
||||
|
||||
testWidgets('Small icons with non-null constraints can be <48dp', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
wrap(
|
||||
child: IconButton(
|
||||
iconSize: 10.0,
|
||||
onPressed: mockOnPressedFunction,
|
||||
icon: const Icon(Icons.link),
|
||||
constraints: const BoxConstraints(),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final RenderBox iconButton = tester.renderObject(find.byType(IconButton));
|
||||
|
||||
// By default IconButton has a padding of 8.0 on all sides, so both
|
||||
// width and height are 10.0 + 2 * 8.0 = 26.0
|
||||
expect(iconButton.size, const Size(26.0, 26.0));
|
||||
});
|
||||
|
||||
testWidgets('Small icons with non-null constraints and custom padding can be <48dp', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
wrap(
|
||||
child: IconButton(
|
||||
iconSize: 10.0,
|
||||
padding: const EdgeInsets.all(3.0),
|
||||
onPressed: mockOnPressedFunction,
|
||||
icon: const Icon(Icons.link),
|
||||
constraints: const BoxConstraints(),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final RenderBox iconButton = tester.renderObject(find.byType(IconButton));
|
||||
|
||||
// This IconButton has a padding of 3.0 on all sides, so both
|
||||
// width and height are 10.0 + 2 * 3.0 = 16.0
|
||||
expect(iconButton.size, const Size(16.0, 16.0));
|
||||
});
|
||||
|
||||
testWidgets('Small icons comply with VisualDensity requirements', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
wrap(
|
||||
child: Theme(
|
||||
data: ThemeData(visualDensity: const VisualDensity(horizontal: 1, vertical: -1)),
|
||||
child: IconButton(
|
||||
iconSize: 10.0,
|
||||
onPressed: mockOnPressedFunction,
|
||||
icon: const Icon(Icons.link),
|
||||
constraints: const BoxConstraints(minWidth: 32.0, minHeight: 32.0),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final RenderBox iconButton = tester.renderObject(find.byType(IconButton));
|
||||
|
||||
// VisualDensity(horizontal: 1, vertical: -1) increases the icon's
|
||||
// width by 4 pixels and decreases its height by 4 pixels, giving
|
||||
// final width 32.0 + 4.0 = 36.0 and
|
||||
// final height 32.0 - 4.0 = 28.0
|
||||
expect(iconButton.size, const Size(36.0, 28.0));
|
||||
});
|
||||
|
||||
testWidgets('test default icon buttons are constrained', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
wrap(
|
||||
|
Loading…
x
Reference in New Issue
Block a user