From 2719f65bd3bb2dec1e41b486b5293cb994c7b153 Mon Sep 17 00:00:00 2001 From: Viren Khatri Date: Wed, 17 Nov 2021 04:22:33 +0530 Subject: [PATCH] Updated IconButton.iconSize to get value from theme (#87643) --- .../flutter/lib/src/material/icon_button.dart | 19 +-- .../test/material/icon_button_test.dart | 113 ++++++++++++++++++ 2 files changed, 123 insertions(+), 9 deletions(-) diff --git a/packages/flutter/lib/src/material/icon_button.dart b/packages/flutter/lib/src/material/icon_button.dart index ce90231083..1515149532 100644 --- a/packages/flutter/lib/src/material/icon_button.dart +++ b/packages/flutter/lib/src/material/icon_button.dart @@ -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, diff --git a/packages/flutter/test/material/icon_button_test.dart b/packages/flutter/test/material/icon_button_test.dart index 18f765f93c..dd5df0f9ec 100644 --- a/packages/flutter/test/material/icon_button_test.dart +++ b/packages/flutter/test/material/icon_button_test.dart @@ -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(