Unverified Commit 06b87fba authored by Qun Cheng's avatar Qun Cheng Committed by GitHub

Update Radio button to material 3 (#111774)

parent ce7789e0
...@@ -31,6 +31,7 @@ import 'package:gen_defaults/input_chip_template.dart'; ...@@ -31,6 +31,7 @@ import 'package:gen_defaults/input_chip_template.dart';
import 'package:gen_defaults/input_decorator_template.dart'; import 'package:gen_defaults/input_decorator_template.dart';
import 'package:gen_defaults/navigation_bar_template.dart'; import 'package:gen_defaults/navigation_bar_template.dart';
import 'package:gen_defaults/navigation_rail_template.dart'; import 'package:gen_defaults/navigation_rail_template.dart';
import 'package:gen_defaults/radio_template.dart';
import 'package:gen_defaults/surface_tint.dart'; import 'package:gen_defaults/surface_tint.dart';
import 'package:gen_defaults/switch_template.dart'; import 'package:gen_defaults/switch_template.dart';
import 'package:gen_defaults/text_field_template.dart'; import 'package:gen_defaults/text_field_template.dart';
...@@ -79,6 +80,7 @@ Future<void> main(List<String> args) async { ...@@ -79,6 +80,7 @@ Future<void> main(List<String> args) async {
'navigation_drawer.json', 'navigation_drawer.json',
'navigation_rail.json', 'navigation_rail.json',
'palette.json', 'palette.json',
'radio_button.json',
'segmented_button_outlined.json', 'segmented_button_outlined.json',
'shape.json', 'shape.json',
'slider.json', 'slider.json',
...@@ -124,6 +126,7 @@ Future<void> main(List<String> args) async { ...@@ -124,6 +126,7 @@ Future<void> main(List<String> args) async {
InputDecoratorTemplate('InputDecorator', '$materialLib/input_decorator.dart', tokens).updateFile(); InputDecoratorTemplate('InputDecorator', '$materialLib/input_decorator.dart', tokens).updateFile();
NavigationBarTemplate('NavigationBar', '$materialLib/navigation_bar.dart', tokens).updateFile(); NavigationBarTemplate('NavigationBar', '$materialLib/navigation_bar.dart', tokens).updateFile();
NavigationRailTemplate('NavigationRail', '$materialLib/navigation_rail.dart', tokens).updateFile(); NavigationRailTemplate('NavigationRail', '$materialLib/navigation_rail.dart', tokens).updateFile();
RadioTemplate('Radio<T>', '$materialLib/radio.dart', tokens).updateFile();
SurfaceTintTemplate('SurfaceTint', '$materialLib/elevation_overlay.dart', tokens).updateFile(); SurfaceTintTemplate('SurfaceTint', '$materialLib/elevation_overlay.dart', tokens).updateFile();
SwitchTemplate('Switch', '$materialLib/switch.dart', tokens).updateFile(); SwitchTemplate('Switch', '$materialLib/switch.dart', tokens).updateFile();
TextFieldTemplate('TextField', '$materialLib/text_field.dart', tokens).updateFile(); TextFieldTemplate('TextField', '$materialLib/text_field.dart', tokens).updateFile();
......
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'template.dart';
class RadioTemplate extends TokenTemplate {
const RadioTemplate(super.blockName, super.fileName, super.tokens, {
super.colorSchemePrefix = '_colors.',
});
@override
String generate() => '''
class _RadioDefaultsM3 extends RadioThemeData {
_RadioDefaultsM3(this.context);
final BuildContext context;
late final ThemeData _theme = Theme.of(context);
late final ColorScheme _colors = _theme.colorScheme;
@override
MaterialStateProperty<Color> get fillColor {
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.selected)) {
if (states.contains(MaterialState.disabled)) {
return ${componentColor('md.comp.radio-button.disabled.selected.icon')};
}
if (states.contains(MaterialState.pressed)) {
return ${componentColor('md.comp.radio-button.selected.pressed.icon')};
}
if (states.contains(MaterialState.hovered)) {
return ${componentColor('md.comp.radio-button.selected.hover.icon')};
}
if (states.contains(MaterialState.focused)) {
return ${componentColor('md.comp.radio-button.selected.focus.icon')};
}
return ${componentColor('md.comp.radio-button.selected.icon')};
}
if (states.contains(MaterialState.disabled)) {
return ${componentColor('md.comp.radio-button.disabled.unselected.icon')};
}
if (states.contains(MaterialState.pressed)) {
return ${componentColor('md.comp.radio-button.unselected.pressed.icon')};
}
if (states.contains(MaterialState.hovered)) {
return ${componentColor('md.comp.radio-button.unselected.hover.icon')};
}
if (states.contains(MaterialState.focused)) {
return ${componentColor('md.comp.radio-button.unselected.focus.icon')};
}
return ${componentColor('md.comp.radio-button.unselected.icon')};
});
}
@override
MaterialStateProperty<Color> get overlayColor {
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.selected)) {
if (states.contains(MaterialState.pressed)) {
return ${componentColor('md.comp.radio-button.selected.pressed.state-layer')};
}
if (states.contains(MaterialState.hovered)) {
return ${componentColor('md.comp.radio-button.selected.hover.state-layer')};
}
if (states.contains(MaterialState.focused)) {
return ${componentColor('md.comp.radio-button.selected.focus.state-layer')};
}
return Colors.transparent;
}
if (states.contains(MaterialState.pressed)) {
return ${componentColor('md.comp.radio-button.unselected.pressed.state-layer')};
}
if (states.contains(MaterialState.hovered)) {
return ${componentColor('md.comp.radio-button.unselected.hover.state-layer')};
}
if (states.contains(MaterialState.focused)) {
return ${componentColor('md.comp.radio-button.unselected.focus.state-layer')};
}
return Colors.transparent;
});
}
@override
MaterialTapTargetSize get materialTapTargetSize => _theme.materialTapTargetSize;
@override
VisualDensity get visualDensity => _theme.visualDensity;
}
''';
}
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'color_scheme.dart';
import 'colors.dart';
import 'constants.dart'; import 'constants.dart';
import 'debug.dart'; import 'debug.dart';
import 'material_state.dart'; import 'material_state.dart';
...@@ -360,30 +362,17 @@ class _RadioState<T> extends State<Radio<T>> with TickerProviderStateMixin, Togg ...@@ -360,30 +362,17 @@ class _RadioState<T> extends State<Radio<T>> with TickerProviderStateMixin, Togg
}); });
} }
MaterialStateProperty<Color> get _defaultFillColor {
final ThemeData themeData = Theme.of(context);
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return themeData.disabledColor;
}
if (states.contains(MaterialState.selected)) {
return themeData.colorScheme.secondary;
}
return themeData.unselectedWidgetColor;
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
assert(debugCheckHasMaterial(context)); assert(debugCheckHasMaterial(context));
final ThemeData themeData = Theme.of(context);
final RadioThemeData radioTheme = RadioTheme.of(context); final RadioThemeData radioTheme = RadioTheme.of(context);
final RadioThemeData defaults = Theme.of(context).useMaterial3 ? _RadioDefaultsM3(context) : _RadioDefaultsM2(context);
final MaterialTapTargetSize effectiveMaterialTapTargetSize = widget.materialTapTargetSize final MaterialTapTargetSize effectiveMaterialTapTargetSize = widget.materialTapTargetSize
?? radioTheme.materialTapTargetSize ?? radioTheme.materialTapTargetSize
?? themeData.materialTapTargetSize; ?? defaults.materialTapTargetSize!;
final VisualDensity effectiveVisualDensity = widget.visualDensity final VisualDensity effectiveVisualDensity = widget.visualDensity
?? radioTheme.visualDensity ?? radioTheme.visualDensity
?? themeData.visualDensity; ?? defaults.visualDensity!;
Size size; Size size;
switch (effectiveMaterialTapTargetSize) { switch (effectiveMaterialTapTargetSize) {
case MaterialTapTargetSize.padded: case MaterialTapTargetSize.padded:
...@@ -405,36 +394,47 @@ class _RadioState<T> extends State<Radio<T>> with TickerProviderStateMixin, Togg ...@@ -405,36 +394,47 @@ class _RadioState<T> extends State<Radio<T>> with TickerProviderStateMixin, Togg
// so that they can be lerped between. // so that they can be lerped between.
final Set<MaterialState> activeStates = states..add(MaterialState.selected); final Set<MaterialState> activeStates = states..add(MaterialState.selected);
final Set<MaterialState> inactiveStates = states..remove(MaterialState.selected); final Set<MaterialState> inactiveStates = states..remove(MaterialState.selected);
final Color effectiveActiveColor = widget.fillColor?.resolve(activeStates) final Color? activeColor = widget.fillColor?.resolve(activeStates)
?? _widgetFillColor.resolve(activeStates) ?? _widgetFillColor.resolve(activeStates)
?? radioTheme.fillColor?.resolve(activeStates) ?? radioTheme.fillColor?.resolve(activeStates);
?? _defaultFillColor.resolve(activeStates); final Color effectiveActiveColor = activeColor ?? defaults.fillColor!.resolve(activeStates)!;
final Color effectiveInactiveColor = widget.fillColor?.resolve(inactiveStates) final Color? inactiveColor = widget.fillColor?.resolve(inactiveStates)
?? _widgetFillColor.resolve(inactiveStates) ?? _widgetFillColor.resolve(inactiveStates)
?? radioTheme.fillColor?.resolve(inactiveStates) ?? radioTheme.fillColor?.resolve(inactiveStates);
?? _defaultFillColor.resolve(inactiveStates); final Color effectiveInactiveColor = inactiveColor ?? defaults.fillColor!.resolve(inactiveStates)!;
final Set<MaterialState> focusedStates = states..add(MaterialState.focused); final Set<MaterialState> focusedStates = states..add(MaterialState.focused);
final Color effectiveFocusOverlayColor = widget.overlayColor?.resolve(focusedStates) Color effectiveFocusOverlayColor = widget.overlayColor?.resolve(focusedStates)
?? widget.focusColor ?? widget.focusColor
?? radioTheme.overlayColor?.resolve(focusedStates) ?? radioTheme.overlayColor?.resolve(focusedStates)
?? themeData.focusColor; ?? defaults.overlayColor!.resolve(focusedStates)!;
final Set<MaterialState> hoveredStates = states..add(MaterialState.hovered); final Set<MaterialState> hoveredStates = states..add(MaterialState.hovered);
final Color effectiveHoverOverlayColor = widget.overlayColor?.resolve(hoveredStates) Color effectiveHoverOverlayColor = widget.overlayColor?.resolve(hoveredStates)
?? widget.hoverColor ?? widget.hoverColor
?? radioTheme.overlayColor?.resolve(hoveredStates) ?? radioTheme.overlayColor?.resolve(hoveredStates)
?? themeData.hoverColor; ?? defaults.overlayColor!.resolve(hoveredStates)!;
final Set<MaterialState> activePressedStates = activeStates..add(MaterialState.pressed); final Set<MaterialState> activePressedStates = activeStates..add(MaterialState.pressed);
final Color effectiveActivePressedOverlayColor = widget.overlayColor?.resolve(activePressedStates) final Color effectiveActivePressedOverlayColor = widget.overlayColor?.resolve(activePressedStates)
?? radioTheme.overlayColor?.resolve(activePressedStates) ?? radioTheme.overlayColor?.resolve(activePressedStates)
?? effectiveActiveColor.withAlpha(kRadialReactionAlpha); ?? activeColor?.withAlpha(kRadialReactionAlpha)
?? defaults.overlayColor!.resolve(activePressedStates)!;
final Set<MaterialState> inactivePressedStates = inactiveStates..add(MaterialState.pressed); final Set<MaterialState> inactivePressedStates = inactiveStates..add(MaterialState.pressed);
final Color effectiveInactivePressedOverlayColor = widget.overlayColor?.resolve(inactivePressedStates) final Color effectiveInactivePressedOverlayColor = widget.overlayColor?.resolve(inactivePressedStates)
?? radioTheme.overlayColor?.resolve(inactivePressedStates) ?? radioTheme.overlayColor?.resolve(inactivePressedStates)
?? effectiveActiveColor.withAlpha(kRadialReactionAlpha); ?? inactiveColor?.withAlpha(kRadialReactionAlpha)
?? defaults.overlayColor!.resolve(inactivePressedStates)!;
if (downPosition != null) {
effectiveHoverOverlayColor = states.contains(MaterialState.selected)
? effectiveActivePressedOverlayColor
: effectiveInactivePressedOverlayColor;
effectiveFocusOverlayColor = states.contains(MaterialState.selected)
? effectiveActivePressedOverlayColor
: effectiveInactivePressedOverlayColor;
}
return Semantics( return Semantics(
inMutuallyExclusiveGroup: true, inMutuallyExclusiveGroup: true,
...@@ -485,3 +485,134 @@ class _RadioPainter extends ToggleablePainter { ...@@ -485,3 +485,134 @@ class _RadioPainter extends ToggleablePainter {
} }
} }
} }
// Hand coded defaults based on Material Design 2.
class _RadioDefaultsM2 extends RadioThemeData {
_RadioDefaultsM2(this.context);
final BuildContext context;
late final ThemeData _theme = Theme.of(context);
late final ColorScheme _colors = _theme.colorScheme;
@override
MaterialStateProperty<Color> get fillColor {
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return _theme.disabledColor;
}
if (states.contains(MaterialState.selected)) {
return _colors.secondary;
}
return _theme.unselectedWidgetColor;
});
}
@override
MaterialStateProperty<Color> get overlayColor {
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.pressed)) {
return fillColor.resolve(states).withAlpha(kRadialReactionAlpha);
}
if (states.contains(MaterialState.focused)) {
return _theme.focusColor;
}
if (states.contains(MaterialState.hovered)) {
return _theme.hoverColor;
}
return Colors.transparent;
});
}
@override
MaterialTapTargetSize get materialTapTargetSize => _theme.materialTapTargetSize;
@override
VisualDensity get visualDensity => _theme.visualDensity;
}
// BEGIN GENERATED TOKEN PROPERTIES - Radio<T>
// Do not edit by hand. The code between the "BEGIN GENERATED" and
// "END GENERATED" comments are generated from data in the Material
// Design token database by the script:
// dev/tools/gen_defaults/bin/gen_defaults.dart.
// Token database version: v0_132
class _RadioDefaultsM3 extends RadioThemeData {
_RadioDefaultsM3(this.context);
final BuildContext context;
late final ThemeData _theme = Theme.of(context);
late final ColorScheme _colors = _theme.colorScheme;
@override
MaterialStateProperty<Color> get fillColor {
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.selected)) {
if (states.contains(MaterialState.disabled)) {
return _colors.onSurface.withOpacity(0.38);
}
if (states.contains(MaterialState.pressed)) {
return _colors.primary;
}
if (states.contains(MaterialState.hovered)) {
return _colors.primary;
}
if (states.contains(MaterialState.focused)) {
return _colors.primary;
}
return _colors.primary;
}
if (states.contains(MaterialState.disabled)) {
return _colors.onSurface.withOpacity(0.38);
}
if (states.contains(MaterialState.pressed)) {
return _colors.onSurface;
}
if (states.contains(MaterialState.hovered)) {
return _colors.onSurface;
}
if (states.contains(MaterialState.focused)) {
return _colors.onSurface;
}
return _colors.onSurfaceVariant;
});
}
@override
MaterialStateProperty<Color> get overlayColor {
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.selected)) {
if (states.contains(MaterialState.pressed)) {
return _colors.onSurface.withOpacity(0.12);
}
if (states.contains(MaterialState.hovered)) {
return _colors.primary.withOpacity(0.08);
}
if (states.contains(MaterialState.focused)) {
return _colors.primary.withOpacity(0.12);
}
return Colors.transparent;
}
if (states.contains(MaterialState.pressed)) {
return _colors.primary.withOpacity(0.12);
}
if (states.contains(MaterialState.hovered)) {
return _colors.onSurface.withOpacity(0.08);
}
if (states.contains(MaterialState.focused)) {
return _colors.onSurface.withOpacity(0.12);
}
return Colors.transparent;
});
}
@override
MaterialTapTargetSize get materialTapTargetSize => _theme.materialTapTargetSize;
@override
VisualDensity get visualDensity => _theme.visualDensity;
}
// END GENERATED TOKEN PROPERTIES - Radio<T>
...@@ -1266,6 +1266,7 @@ class ThemeData with Diagnosticable { ...@@ -1266,6 +1266,7 @@ class ThemeData with Diagnosticable {
/// * Lists: [ListTile] /// * Lists: [ListTile]
/// * Navigation bar: [NavigationBar] (new, replacing [BottomNavigationBar]) /// * Navigation bar: [NavigationBar] (new, replacing [BottomNavigationBar])
/// * [Navigation rail](https://m3.material.io/components/navigation-rail): [NavigationRail] /// * [Navigation rail](https://m3.material.io/components/navigation-rail): [NavigationRail]
/// * Radio button: [Radio]
/// * Switch: [Switch] /// * Switch: [Switch]
/// * Top app bar: [AppBar] /// * Top app bar: [AppBar]
/// ///
......
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