diff --git a/packages/flutter/lib/src/material/radio.dart b/packages/flutter/lib/src/material/radio.dart index 850a6815261..9a8e70e67b3 100644 --- a/packages/flutter/lib/src/material/radio.dart +++ b/packages/flutter/lib/src/material/radio.dart @@ -426,9 +426,11 @@ class Radio extends StatefulWidget { /// * [WidgetState.hovered]. /// * [WidgetState.focused]. /// * [WidgetState.disabled]. - /// - /// If null, then it is transparent in all states. /// {@endtemplate} + /// + /// If null, then [RadioThemeData.backgroundColor] of [ThemeData.radioTheme] + /// is used. If that is also null the default value is transparent in all + /// states. final WidgetStateProperty? backgroundColor; /// {@template flutter.material.Radio.side} @@ -443,20 +445,23 @@ class Radio extends StatefulWidget { /// * [WidgetState.hovered]. /// * [WidgetState.focused]. /// * [WidgetState.disabled]. + /// {@endtemplate} /// /// If null, then [RadioThemeData.side] of [ThemeData.radioTheme] is used. If /// that is also null, the default value is a border using the fill color. - /// {@endtemplate} final BorderSide? side; + /// {@template flutter.material.Radio.innerRadius} /// The radius of the inner circle of the radio button, in all [WidgetState]s. /// /// Resolves in the following states: /// * [WidgetState.hovered]. /// * [WidgetState.focused]. /// * [WidgetState.disabled]. + /// {@endtemplate} /// - /// If null, then it defaults to `4.5` in all states. + /// If null, then [RadioThemeData.innerRadius] of [ThemeData.radioTheme] is + /// used. If that is also null, the default value is `4.5` in all states. final WidgetStateProperty? innerRadius; @override @@ -761,7 +766,10 @@ class _RadioPaintState extends State<_RadioPaint> { strokeAlign: BorderSide.strokeAlignCenter, ); - final double innerRadius = widget.innerRadius?.resolve(activeStates) ?? _kInnerRadius; + final double innerRadius = + widget.innerRadius?.resolve(activeStates) ?? + radioTheme.innerRadius?.resolve(activeStates) ?? + _kInnerRadius; return CustomPaint( size: size, diff --git a/packages/flutter/lib/src/material/radio_theme.dart b/packages/flutter/lib/src/material/radio_theme.dart index 6278273c1f7..ffecfcaeb2c 100644 --- a/packages/flutter/lib/src/material/radio_theme.dart +++ b/packages/flutter/lib/src/material/radio_theme.dart @@ -51,6 +51,7 @@ class RadioThemeData with Diagnosticable { this.visualDensity, this.backgroundColor, this.side, + this.innerRadius, }); /// {@macro flutter.widget.RawRadio.mouseCursor} @@ -89,11 +90,23 @@ class RadioThemeData with Diagnosticable { final VisualDensity? visualDensity; /// {@macro flutter.material.Radio.backgroundColor} + /// + /// If specified, overrides the default value of [Radio.backgroundColor]. The + /// default value is transparent in all states. final WidgetStateProperty? backgroundColor; /// {@macro flutter.material.Radio.side} + /// + /// If specified, overrides the default value of [Radio.side]. The default + /// value is a border using the fill color. final BorderSide? side; + /// {@macro flutter.material.Radio.innerRadius} + /// + /// If specified, overrides the default value of [Radio.innerRadius]. The + /// default value is `4.5` in all states. + final WidgetStateProperty? innerRadius; + /// Creates a copy of this object but with the given fields replaced with the /// new values. RadioThemeData copyWith({ @@ -105,6 +118,7 @@ class RadioThemeData with Diagnosticable { VisualDensity? visualDensity, WidgetStateProperty? backgroundColor, BorderSide? side, + WidgetStateProperty? innerRadius, }) { return RadioThemeData( mouseCursor: mouseCursor ?? this.mouseCursor, @@ -115,6 +129,7 @@ class RadioThemeData with Diagnosticable { visualDensity: visualDensity ?? this.visualDensity, backgroundColor: backgroundColor ?? this.backgroundColor, side: side ?? this.side, + innerRadius: innerRadius ?? this.innerRadius, ); } @@ -144,9 +159,9 @@ class RadioThemeData with Diagnosticable { } return RadioThemeData( mouseCursor: t < 0.5 ? a?.mouseCursor : b?.mouseCursor, - fillColor: MaterialStateProperty.lerp(a?.fillColor, b?.fillColor, t, Color.lerp), + fillColor: WidgetStateProperty.lerp(a?.fillColor, b?.fillColor, t, Color.lerp), materialTapTargetSize: t < 0.5 ? a?.materialTapTargetSize : b?.materialTapTargetSize, - overlayColor: MaterialStateProperty.lerp( + overlayColor: WidgetStateProperty.lerp( a?.overlayColor, b?.overlayColor, t, @@ -161,6 +176,7 @@ class RadioThemeData with Diagnosticable { Color.lerp, ), side: _lerpSides(a?.side, b?.side, t), + innerRadius: WidgetStateProperty.lerp(a?.innerRadius, b?.innerRadius, t, lerpDouble), ); } @@ -174,6 +190,7 @@ class RadioThemeData with Diagnosticable { visualDensity, backgroundColor, side, + innerRadius, ); @override @@ -192,28 +209,25 @@ class RadioThemeData with Diagnosticable { other.materialTapTargetSize == materialTapTargetSize && other.visualDensity == visualDensity && other.backgroundColor == backgroundColor && - other.side == side; + other.side == side && + other.innerRadius == innerRadius; } @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties.add( - DiagnosticsProperty>( + DiagnosticsProperty>( 'mouseCursor', mouseCursor, defaultValue: null, ), ); properties.add( - DiagnosticsProperty>( - 'fillColor', - fillColor, - defaultValue: null, - ), + DiagnosticsProperty>('fillColor', fillColor, defaultValue: null), ); properties.add( - DiagnosticsProperty>( + DiagnosticsProperty>( 'overlayColor', overlayColor, defaultValue: null, @@ -238,6 +252,13 @@ class RadioThemeData with Diagnosticable { ), ); properties.add(DiagnosticsProperty('side', side, defaultValue: null)); + properties.add( + DiagnosticsProperty>( + 'innerRadius', + innerRadius, + defaultValue: null, + ), + ); } } diff --git a/packages/flutter/test/material/radio_theme_test.dart b/packages/flutter/test/material/radio_theme_test.dart index d52520d5e7d..a4af470f0cc 100644 --- a/packages/flutter/test/material/radio_theme_test.dart +++ b/packages/flutter/test/material/radio_theme_test.dart @@ -29,6 +29,7 @@ void main() { expect(themeData.visualDensity, null); expect(themeData.backgroundColor, null); expect(themeData.side, null); + expect(themeData.innerRadius, null); const RadioTheme theme = RadioTheme(data: RadioThemeData(), child: SizedBox()); expect(theme.data.mouseCursor, null); @@ -39,6 +40,7 @@ void main() { expect(theme.data.visualDensity, null); expect(theme.data.backgroundColor, null); expect(theme.data.side, null); + expect(theme.data.innerRadius, null); }); testWidgets('Default RadioThemeData debugFillProperties', (WidgetTester tester) async { @@ -64,6 +66,7 @@ void main() { visualDensity: VisualDensity.standard, backgroundColor: WidgetStatePropertyAll(Color(0xfffffff2)), side: BorderSide(color: Color(0xfffffff3), width: 2), + innerRadius: WidgetStatePropertyAll(5.0), ).debugFillProperties(builder); final List description = builder.properties @@ -82,6 +85,7 @@ void main() { 'visualDensity: VisualDensity#00000(h: 0.0, v: 0.0)', 'backgroundColor: WidgetStatePropertyAll(${const Color(0xfffffff2)})', 'side: BorderSide(color: ${const Color(0xfffffff3)}, width: 2.0)', + 'innerRadius: WidgetStatePropertyAll(5.0)', ]), ); }); @@ -99,6 +103,7 @@ void main() { const double splashRadius = 1.0; const MaterialTapTargetSize materialTapTargetSize = MaterialTapTargetSize.shrinkWrap; const VisualDensity visualDensity = VisualDensity(horizontal: 1, vertical: 1); + const double innerRadius = 5.0; Widget buildRadio({bool selected = false, bool autofocus = false}) { return MaterialApp( @@ -129,6 +134,7 @@ void main() { } return defaultBackgroundColor; }), + innerRadius: const WidgetStatePropertyAll(innerRadius), ), ), home: Scaffold( @@ -161,7 +167,8 @@ void main() { _getRadioMaterial(tester), paints ..circle(color: selectedBackgroundColor) - ..circle(color: selectedFillColor), + ..circle(color: selectedFillColor) + ..circle(color: selectedFillColor, radius: innerRadius), ); // Radio with hover. @@ -243,6 +250,7 @@ void main() { const double themeSplashRadius = 1.0; const MaterialTapTargetSize themeMaterialTapTargetSize = MaterialTapTargetSize.padded; const VisualDensity themeVisualDensity = VisualDensity.standard; + const double themeInnerRadius = 5.0; const MouseCursor mouseCursor = SystemMouseCursors.text; const Color defaultFillColor = Color(0xeffffff0); @@ -254,6 +262,7 @@ void main() { const double splashRadius = 2.0; const MaterialTapTargetSize materialTapTargetSize = MaterialTapTargetSize.shrinkWrap; const VisualDensity visualDensity = VisualDensity(horizontal: 1, vertical: 1); + const double innerRadius = 6.0; Widget buildRadio({bool selected = false, bool autofocus = false}) { return MaterialApp( @@ -284,6 +293,7 @@ void main() { } return themeDefaultBackgroundColor; }), + innerRadius: const WidgetStatePropertyAll(themeInnerRadius), ), ), home: Scaffold( @@ -310,6 +320,7 @@ void main() { } return defaultBackgroundColor; }), + innerRadius: const WidgetStatePropertyAll(innerRadius), ), ), ); @@ -334,7 +345,8 @@ void main() { _getRadioMaterial(tester), paints ..circle(color: selectedBackgroundColor) - ..circle(color: selectedFillColor), + ..circle(color: selectedFillColor) + ..circle(color: selectedFillColor, radius: innerRadius), ); // Radio with hover.