Updated IconButton.iconSize to get value from theme (#87643)

This commit is contained in:
Viren Khatri 2021-11-17 04:22:33 +05:30 committed by GitHub
parent c7572150fa
commit 2719f65bd3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 123 additions and 9 deletions

View file

@ -116,7 +116,7 @@ class IconButton extends StatelessWidget {
/// or an [ImageIcon].
const IconButton({
Key? key,
this.iconSize = 24.0,
this.iconSize,
this.visualDensity,
this.padding = const EdgeInsets.all(8.0),
this.alignment = Alignment.center,
@ -135,8 +135,7 @@ class IconButton extends StatelessWidget {
this.enableFeedback = true,
this.constraints,
required this.icon,
}) : assert(iconSize != null),
assert(padding != null),
}) : assert(padding != null),
assert(alignment != null),
assert(splashRadius == null || splashRadius > 0),
assert(autofocus != null),
@ -145,7 +144,8 @@ class IconButton extends StatelessWidget {
/// The size of the icon inside the button.
///
/// This property must not be null. It defaults to 24.0.
/// If null, uses [IconThemeData.size]. If it is also null, the default size
/// is 24.0.
///
/// The size given here is passed down to the widget in the [icon] property
/// via an [IconTheme]. Setting the size here instead of in, for example, the
@ -153,7 +153,7 @@ class IconButton extends StatelessWidget {
/// fit the [Icon]. If you were to set the size of the [Icon] using
/// [Icon.size] instead, then the [IconButton] would default to 24.0 and then
/// the [Icon] itself would likely get clipped.
final double iconSize;
final double? iconSize;
/// Defines how compact the icon button's layout will be.
///
@ -319,19 +319,20 @@ class IconButton extends StatelessWidget {
minHeight: _kMinButtonSize,
);
final BoxConstraints adjustedConstraints = effectiveVisualDensity.effectiveConstraints(unadjustedConstraints);
final double effectiveIconSize = iconSize ?? IconTheme.of(context).size ?? 24.0;
Widget result = ConstrainedBox(
constraints: adjustedConstraints,
child: Padding(
padding: padding,
child: SizedBox(
height: iconSize,
width: iconSize,
height: effectiveIconSize,
width: effectiveIconSize,
child: Align(
alignment: alignment,
child: IconTheme.merge(
data: IconThemeData(
size: iconSize,
size: effectiveIconSize,
color: currentColor,
),
child: icon,
@ -364,7 +365,7 @@ class IconButton extends StatelessWidget {
splashColor: splashColor ?? theme.splashColor,
radius: splashRadius ?? math.max(
Material.defaultSplashRadius,
(iconSize + math.min(padding.horizontal, padding.vertical)) * 0.7,
(effectiveIconSize + math.min(padding.horizontal, padding.vertical)) * 0.7,
// x 0.5 for diameter -> radius and + 40% overflow derived from other Material apps.
),
child: result,

View file

@ -75,6 +75,119 @@ void main() {
expect(iconButton.size, const Size(70.0, 70.0));
});
testWidgets('when both iconSize and IconTheme.of(context).size are null, size falls back to 24.0', (WidgetTester tester) async {
final FocusNode focusNode = FocusNode(debugLabel: 'Ink Focus');
await tester.pumpWidget(
wrap(
child: IconTheme(
data: const IconThemeData(size: null),
child: IconButton(
focusNode: focusNode,
onPressed: mockOnPressedFunction.handler,
icon: const Icon(Icons.link),
),
)
),
);
final RenderBox icon = tester.renderObject(find.byType(Icon));
expect(icon.size, const Size(24.0, 24.0));
});
testWidgets('when null, iconSize is overridden by closest IconTheme', (WidgetTester tester) async {
RenderBox icon;
await tester.pumpWidget(
wrap(
child: IconTheme(
data: const IconThemeData(size: 10),
child: IconButton(
onPressed: mockOnPressedFunction.handler,
icon: const Icon(Icons.link),
),
)
),
);
icon = tester.renderObject(find.byType(Icon));
expect(icon.size, const Size(10.0, 10.0));
await tester.pumpWidget(
wrap(
child: Theme(
data: ThemeData(
iconTheme: const IconThemeData(size: 10),
),
child: IconButton(
onPressed: mockOnPressedFunction.handler,
icon: const Icon(Icons.link),
),
)
),
);
icon = tester.renderObject(find.byType(Icon));
expect(icon.size, const Size(10.0, 10.0));
await tester.pumpWidget(
wrap(
child: Theme(
data: ThemeData(
iconTheme: const IconThemeData(size: 20),
),
child: IconTheme(
data: const IconThemeData(size: 10),
child: IconButton(
onPressed: mockOnPressedFunction.handler,
icon: const Icon(Icons.link),
),
),
)
),
);
icon = tester.renderObject(find.byType(Icon));
expect(icon.size, const Size(10.0, 10.0));
await tester.pumpWidget(
wrap(
child: IconTheme(
data: const IconThemeData(size: 20),
child: Theme(
data: ThemeData(
iconTheme: const IconThemeData(size: 10),
),
child: IconButton(
onPressed: mockOnPressedFunction.handler,
icon: const Icon(Icons.link),
),
),
)
),
);
icon = tester.renderObject(find.byType(Icon));
expect(icon.size, const Size(10.0, 10.0));
});
testWidgets('when non-null, iconSize precedes IconTheme.of(context).size', (WidgetTester tester) async {
await tester.pumpWidget(
wrap(
child: IconTheme(
data: const IconThemeData(size: 30.0),
child: IconButton(
iconSize: 10.0,
onPressed: mockOnPressedFunction.handler,
icon: const Icon(Icons.link),
),
)
),
);
final RenderBox icon = tester.renderObject(find.byType(Icon));
expect(icon.size, const Size(10.0, 10.0));
});
testWidgets('Small icons with non-null constraints can be <48dp', (WidgetTester tester) async {
await tester.pumpWidget(
wrap(