Unverified Commit ed8468b9 authored by Taha Tesser's avatar Taha Tesser Committed by GitHub

Add `splashRadius` property to `IconTheme` (#93478)

parent b865e23a
......@@ -29,7 +29,7 @@ class CupertinoIconThemeData extends IconThemeData with Diagnosticable {
/// Creates a copy of this icon theme but with the given fields replaced with
/// the new values.
@override
CupertinoIconThemeData copyWith({ Color? color, double? opacity, double? size }) {
CupertinoIconThemeData copyWith({ Color? color, double? opacity, double? size, double? splashRadius }) {
return CupertinoIconThemeData(
color: color ?? this.color,
opacity: opacity ?? this.opacity,
......
......@@ -306,6 +306,7 @@ class IconButton extends StatelessWidget {
Widget build(BuildContext context) {
assert(debugCheckHasMaterial(context));
final ThemeData theme = Theme.of(context);
final IconThemeData iconTheme = IconTheme.of(context);
Color? currentColor;
if (onPressed != null)
currentColor = color;
......@@ -319,7 +320,7 @@ class IconButton extends StatelessWidget {
minHeight: _kMinButtonSize,
);
final BoxConstraints adjustedConstraints = effectiveVisualDensity.effectiveConstraints(unadjustedConstraints);
final double effectiveIconSize = iconSize ?? IconTheme.of(context).size ?? 24.0;
final double effectiveIconSize = iconSize ?? iconTheme.size ?? 24.0;
Widget result = ConstrainedBox(
constraints: adjustedConstraints,
......@@ -363,11 +364,12 @@ class IconButton extends StatelessWidget {
hoverColor: hoverColor ?? theme.hoverColor,
highlightColor: highlightColor ?? theme.highlightColor,
splashColor: splashColor ?? theme.splashColor,
radius: splashRadius ?? math.max(
Material.defaultSplashRadius,
(effectiveIconSize + math.min(padding.horizontal, padding.vertical)) * 0.7,
// x 0.5 for diameter -> radius and + 40% overflow derived from other Material apps.
),
radius: splashRadius ?? iconTheme.splashRadius ??
math.max(
Material.defaultSplashRadius,
(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,
),
);
......
......@@ -23,7 +23,7 @@ class IconThemeData with Diagnosticable {
///
/// The opacity applies to both explicit and default icon colors. The value
/// is clamped between 0.0 and 1.0.
const IconThemeData({this.color, double? opacity, this.size}) : _opacity = opacity;
const IconThemeData({this.color, double? opacity, this.size, this.splashRadius}) : _opacity = opacity;
/// Creates an icon theme with some reasonable default values.
///
......@@ -31,15 +31,17 @@ class IconThemeData with Diagnosticable {
const IconThemeData.fallback()
: color = const Color(0xFF000000),
_opacity = 1.0,
size = 24.0;
size = 24.0,
splashRadius = null;
/// Creates a copy of this icon theme but with the given fields replaced with
/// the new values.
IconThemeData copyWith({ Color? color, double? opacity, double? size }) {
IconThemeData copyWith({ Color? color, double? opacity, double? size, double? splashRadius }) {
return IconThemeData(
color: color ?? this.color,
opacity: opacity ?? this.opacity,
size: size ?? this.size,
splashRadius: splashRadius ?? this.splashRadius,
);
}
......@@ -53,6 +55,7 @@ class IconThemeData with Diagnosticable {
color: other.color,
opacity: other.opacity,
size: other.size,
splashRadius: other.splashRadius,
);
}
......@@ -87,6 +90,9 @@ class IconThemeData with Diagnosticable {
/// The default size for icons.
final double? size;
/// The default splash radius for [IconButton]s.
final double? splashRadius;
/// Linearly interpolate between two icon theme data objects.
///
/// {@macro dart.ui.shadow.lerp}
......@@ -96,6 +102,7 @@ class IconThemeData with Diagnosticable {
color: Color.lerp(a?.color, b?.color, t),
opacity: ui.lerpDouble(a?.opacity, b?.opacity, t),
size: ui.lerpDouble(a?.size, b?.size, t),
splashRadius: ui.lerpDouble(a?.splashRadius, b?.splashRadius, t),
);
}
......@@ -106,11 +113,12 @@ class IconThemeData with Diagnosticable {
return other is IconThemeData
&& other.color == color
&& other.opacity == opacity
&& other.size == size;
&& other.size == size
&& other.splashRadius == splashRadius;
}
@override
int get hashCode => hashValues(color, opacity, size);
int get hashCode => hashValues(color, opacity, size, splashRadius);
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
......@@ -118,5 +126,6 @@ class IconThemeData with Diagnosticable {
properties.add(ColorProperty('color', color, defaultValue: null));
properties.add(DoubleProperty('opacity', opacity, defaultValue: null));
properties.add(DoubleProperty('size', size, defaultValue: null));
properties.add(DoubleProperty('splashRadius', splashRadius, defaultValue: null));
}
}
......@@ -480,6 +480,40 @@ void main() {
await gesture.up();
});
testWidgets('IconButton can inherit splashRadius from IconTheme', (WidgetTester tester) async {
const double splashRadius = 30.0;
await tester.pumpWidget(
MaterialApp(
home: Material(
child: Center(
child: IconTheme(
data: const IconThemeData(
splashRadius: splashRadius,
),
child: IconButton(
icon: const Icon(Icons.android),
onPressed: () { /* enable the button */ },
),
),
),
),
),
);
final Offset center = tester.getCenter(find.byType(IconButton));
final TestGesture gesture = await tester.startGesture(center);
await tester.pump(); // Start gesture.
await tester.pump(const Duration(milliseconds: 1000)); // Wait for splash to be well under way.
expect(
Material.of(tester.element(find.byType(IconButton))),
paints
..circle(radius: splashRadius),
);
await gesture.up();
});
testWidgets('IconButton Semantics (enabled)', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester);
......
......@@ -7,7 +7,7 @@ import 'package:flutter_test/flutter_test.dart';
void main() {
test('IconThemeData control test', () {
const IconThemeData data = IconThemeData(color: Color(0xAAAAAAAA), opacity: 0.5, size: 16.0);
const IconThemeData data = IconThemeData(color: Color(0xAAAAAAAA), opacity: 0.5, size: 16.0, splashRadius: 30.0);
expect(data, hasOneLineDescription);
expect(data, equals(data.copyWith()));
......@@ -17,24 +17,27 @@ void main() {
expect(lerped.color, const Color(0xBF7F7F7F));
expect(lerped.opacity, 0.625);
expect(lerped.size, 18.0);
expect(lerped.splashRadius, 22.5);
});
test('IconThemeData lerp with first null', () {
const IconThemeData data = IconThemeData(color: Color(0xFFFFFFFF), opacity: 1.0, size: 16.0);
const IconThemeData data = IconThemeData(color: Color(0xFFFFFFFF), opacity: 1.0, size: 16.0, splashRadius: 30.0);
final IconThemeData lerped = IconThemeData.lerp(null, data, 0.25);
expect(lerped.color, const Color(0x40FFFFFF));
expect(lerped.opacity, 0.25);
expect(lerped.size, 4.0);
expect(lerped.splashRadius, 7.5);
});
test('IconThemeData lerp with second null', () {
const IconThemeData data = IconThemeData(color: Color(0xFFFFFFFF), opacity: 1.0, size: 16.0);
const IconThemeData data = IconThemeData(color: Color(0xFFFFFFFF), opacity: 1.0, size: 16.0, splashRadius: 30.0);
final IconThemeData lerped = IconThemeData.lerp(data, null, 0.25);
expect(lerped.color, const Color(0xBFFFFFFF));
expect(lerped.opacity, 0.75);
expect(lerped.size, 12.0);
expect(lerped.splashRadius, 22.5);
});
test('IconThemeData lerp with both null', () {
......@@ -42,5 +45,6 @@ void main() {
expect(lerped.color, null);
expect(lerped.opacity, null);
expect(lerped.size, null);
expect(lerped.splashRadius, null);
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment