diff --git a/packages/flutter/lib/src/material/button_style.dart b/packages/flutter/lib/src/material/button_style.dart index 9d999b5ab99..4dbe8883606 100644 --- a/packages/flutter/lib/src/material/button_style.dart +++ b/packages/flutter/lib/src/material/button_style.dart @@ -603,30 +603,6 @@ class ButtonStyle with Diagnosticable { if (a == null && b == null) { return null; } - return _LerpSides(a, b, t); - } -} - -class _LerpSides implements MaterialStateProperty { - const _LerpSides(this.a, this.b, this.t); - - final MaterialStateProperty? a; - final MaterialStateProperty? b; - final double t; - - @override - BorderSide? resolve(Set states) { - final BorderSide? resolvedA = a?.resolve(states); - final BorderSide? resolvedB = b?.resolve(states); - if (resolvedA == null && resolvedB == null) { - return null; - } - if (resolvedA == null) { - return BorderSide.lerp(BorderSide(width: 0, color: resolvedB!.color.withAlpha(0)), resolvedB, t); - } - if (resolvedB == null) { - return BorderSide.lerp(resolvedA, BorderSide(width: 0, color: resolvedA.color.withAlpha(0)), t); - } - return BorderSide.lerp(resolvedA, resolvedB, t); + return MaterialStateBorderSide.lerp(a, b, t); } } diff --git a/packages/flutter/lib/src/material/menu_style.dart b/packages/flutter/lib/src/material/menu_style.dart index aa4dcb12ba4..2325b85baee 100644 --- a/packages/flutter/lib/src/material/menu_style.dart +++ b/packages/flutter/lib/src/material/menu_style.dart @@ -316,7 +316,7 @@ class MenuStyle with Diagnosticable { minimumSize: MaterialStateProperty.lerp(a?.minimumSize, b?.minimumSize, t, Size.lerp), fixedSize: MaterialStateProperty.lerp(a?.fixedSize, b?.fixedSize, t, Size.lerp), maximumSize: MaterialStateProperty.lerp(a?.maximumSize, b?.maximumSize, t, Size.lerp), - side: _LerpSides(a?.side, b?.side, t), + side: MaterialStateBorderSide.lerp(a?.side, b?.side, t), shape: MaterialStateProperty.lerp(a?.shape, b?.shape, t, OutlinedBorder.lerp), mouseCursor: t < 0.5 ? a?.mouseCursor : b?.mouseCursor, visualDensity: t < 0.5 ? a?.visualDensity : b?.visualDensity, @@ -342,29 +342,3 @@ class MenuStyle with Diagnosticable { properties.add(DiagnosticsProperty('alignment', alignment, defaultValue: null)); } } - -/// A required helper class because [BorderSide.lerp] doesn't support passing or -/// returning null values. -class _LerpSides implements MaterialStateProperty { - const _LerpSides(this.a, this.b, this.t); - - final MaterialStateProperty? a; - final MaterialStateProperty? b; - final double t; - - @override - BorderSide? resolve(Set states) { - final BorderSide? resolvedA = a?.resolve(states); - final BorderSide? resolvedB = b?.resolve(states); - if (resolvedA == null && resolvedB == null) { - return null; - } - if (resolvedA == null) { - return BorderSide.lerp(BorderSide(width: 0, color: resolvedB!.color.withAlpha(0)), resolvedB, t); - } - if (resolvedB == null) { - return BorderSide.lerp(resolvedA, BorderSide(width: 0, color: resolvedA.color.withAlpha(0)), t); - } - return BorderSide.lerp(resolvedA, resolvedB, t); - } -} diff --git a/packages/flutter/lib/src/material/search_bar_theme.dart b/packages/flutter/lib/src/material/search_bar_theme.dart index 3599a4130d5..8e54ff53508 100644 --- a/packages/flutter/lib/src/material/search_bar_theme.dart +++ b/packages/flutter/lib/src/material/search_bar_theme.dart @@ -203,31 +203,7 @@ class SearchBarThemeData with Diagnosticable { if (identical(a, b)) { return a; } - return _LerpSides(a, b, t); - } -} - -class _LerpSides implements MaterialStateProperty { - const _LerpSides(this.a, this.b, this.t); - - final MaterialStateProperty? a; - final MaterialStateProperty? b; - final double t; - - @override - BorderSide? resolve(Set states) { - final BorderSide? resolvedA = a?.resolve(states); - final BorderSide? resolvedB = b?.resolve(states); - if (identical(resolvedA, resolvedB)) { - return resolvedA; - } - if (resolvedA == null) { - return BorderSide.lerp(BorderSide(width: 0, color: resolvedB!.color.withAlpha(0)), resolvedB, t); - } - if (resolvedB == null) { - return BorderSide.lerp(resolvedA, BorderSide(width: 0, color: resolvedA.color.withAlpha(0)), t); - } - return BorderSide.lerp(resolvedA, resolvedB, t); + return MaterialStateBorderSide.lerp(a, b, t); } } diff --git a/packages/flutter/lib/src/widgets/widget_state.dart b/packages/flutter/lib/src/widgets/widget_state.dart index 6d30f56b353..9e4b5d924a2 100644 --- a/packages/flutter/lib/src/widgets/widget_state.dart +++ b/packages/flutter/lib/src/widgets/widget_state.dart @@ -353,6 +353,43 @@ abstract class WidgetStateBorderSide extends BorderSide implements WidgetStatePr /// widget or theme. @override BorderSide? resolve(Set states); + + /// Linearly interpolate between two [WidgetStateProperty]s of [BorderSide]. + static WidgetStateProperty? lerp( + WidgetStateProperty? a, + WidgetStateProperty? b, + double t, + ) { + // Avoid creating a _LerpSides object for a common case. + if (a == null && b == null) { + return null; + } + return _LerpSides(a, b, t); + } +} + +class _LerpSides implements WidgetStateProperty { + const _LerpSides(this.a, this.b, this.t); + + final WidgetStateProperty? a; + final WidgetStateProperty? b; + final double t; + + @override + BorderSide? resolve(Set states) { + final BorderSide? resolvedA = a?.resolve(states); + final BorderSide? resolvedB = b?.resolve(states); + if (resolvedA == null && resolvedB == null) { + return null; + } + if (resolvedA == null) { + return BorderSide.lerp(BorderSide(width: 0, color: resolvedB!.color.withAlpha(0)), resolvedB, t); + } + if (resolvedB == null) { + return BorderSide.lerp(resolvedA, BorderSide(width: 0, color: resolvedA.color.withAlpha(0)), t); + } + return BorderSide.lerp(resolvedA, resolvedB, t); + } } class _WidgetStateBorderSide extends WidgetStateBorderSide { diff --git a/packages/flutter/test/widgets/widget_state_property_test.dart b/packages/flutter/test/widgets/widget_state_property_test.dart index 0eaeaaeaacd..9bf1a24f828 100644 --- a/packages/flutter/test/widgets/widget_state_property_test.dart +++ b/packages/flutter/test/widgets/widget_state_property_test.dart @@ -86,6 +86,48 @@ void main() { )!.resolve(enabled)!; expect(textStyle.fontSize, 20.0); }); + + test('WidgetStateBorderSide.lerp()', () { + const WidgetStateProperty borderSide1 = WidgetStatePropertyAll( + BorderSide( + color: Color(0xffff0000), + width: 4.0, + ), + ); + const WidgetStateProperty borderSide2 = WidgetStatePropertyAll( + BorderSide( + color: Color(0xff0000ff), + width: 12.0, + ), + ); + + // Using `0.0` interpolation value. + BorderSide borderSide = WidgetStateBorderSide.lerp( + borderSide1, + borderSide2, + 0.0, + )!.resolve(enabled)!; + expect(borderSide.color, const Color(0xffff0000)); + expect(borderSide.width, 4.0); + + // Using `0.5` interpolation value. + borderSide = WidgetStateBorderSide.lerp( + borderSide1, + borderSide2, + 0.5, + )!.resolve(enabled)!; + expect(borderSide.color, const Color(0xff7f007f)); + expect(borderSide.width, 8.0); + + // Using `1.0` interpolation value. + borderSide = WidgetStateBorderSide.lerp( + borderSide1, + borderSide2, + 1.0, + )!.resolve(enabled)!; + expect(borderSide.color, const Color(0xff0000ff)); + expect(borderSide.width, 12.0); + }); } Set enabled = {};