Unverified Commit 75fac6ae authored by Qun Cheng's avatar Qun Cheng Committed by GitHub

Migrated `Switch` to Material 3 (#110095)

parent e3f8ee88
......@@ -31,6 +31,7 @@ import 'package:gen_defaults/input_decorator_template.dart';
import 'package:gen_defaults/navigation_bar_template.dart';
import 'package:gen_defaults/navigation_rail_template.dart';
import 'package:gen_defaults/surface_tint.dart';
import 'package:gen_defaults/switch_template.dart';
import 'package:gen_defaults/text_field_template.dart';
import 'package:gen_defaults/typography_template.dart';
......@@ -121,6 +122,7 @@ Future<void> main(List<String> args) async {
NavigationBarTemplate('NavigationBar', '$materialLib/navigation_bar.dart', tokens).updateFile();
NavigationRailTemplate('NavigationRail', '$materialLib/navigation_rail.dart', tokens).updateFile();
SurfaceTintTemplate('SurfaceTint', '$materialLib/elevation_overlay.dart', tokens).updateFile();
SwitchTemplate('Switch', '$materialLib/switch.dart', tokens).updateFile();
TextFieldTemplate('TextField', '$materialLib/text_field.dart', tokens).updateFile();
TypographyTemplate('Typography', '$materialLib/typography.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 SwitchTemplate extends TokenTemplate {
const SwitchTemplate(super.blockName, super.fileName, super.tokens, {
super.colorSchemePrefix = '_colors.',
});
@override
String generate() => '''
class _${blockName}DefaultsM3 extends SwitchThemeData {
_${blockName}DefaultsM3(BuildContext context)
: _colors = Theme.of(context).colorScheme;
final ColorScheme _colors;
@override
MaterialStateProperty<Color> get thumbColor {
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
if (states.contains(MaterialState.selected)) {
return ${componentColor('md.comp.switch.disabled.selected.handle')};
}
return ${componentColor('md.comp.switch.disabled.unselected.handle')};
}
if (states.contains(MaterialState.selected)) {
if (states.contains(MaterialState.pressed)) {
return ${componentColor('md.comp.switch.selected.pressed.handle')};
}
if (states.contains(MaterialState.hovered)) {
return ${componentColor('md.comp.switch.selected.hover.handle')};
}
if (states.contains(MaterialState.focused)) {
return ${componentColor('md.comp.switch.selected.focus.handle')};
}
return ${componentColor('md.comp.switch.selected.handle')};
}
if (states.contains(MaterialState.pressed)) {
return ${componentColor('md.comp.switch.unselected.pressed.handle')};
}
if (states.contains(MaterialState.hovered)) {
return ${componentColor('md.comp.switch.unselected.hover.handle')};
}
if (states.contains(MaterialState.focused)) {
return ${componentColor('md.comp.switch.unselected.focus.handle')};
}
return ${componentColor('md.comp.switch.unselected.handle')};
});
}
@override
MaterialStateProperty<Color> get trackColor {
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
if (states.contains(MaterialState.selected)) {
return ${componentColor('md.comp.switch.disabled.selected.track')}.withOpacity(${opacity('md.comp.switch.disabled.track.opacity')});
}
return ${componentColor('md.comp.switch.disabled.unselected.track')}.withOpacity(${opacity('md.comp.switch.disabled.track.opacity')});
}
if (states.contains(MaterialState.selected)) {
if (states.contains(MaterialState.pressed)) {
return ${componentColor('md.comp.switch.selected.pressed.track')};
}
if (states.contains(MaterialState.hovered)) {
return ${componentColor('md.comp.switch.selected.hover.track')};
}
if (states.contains(MaterialState.focused)) {
return ${componentColor('md.comp.switch.selected.focus.track')};
}
return ${componentColor('md.comp.switch.selected.track')};
}
if (states.contains(MaterialState.pressed)) {
return ${componentColor('md.comp.switch.unselected.pressed.track')};
}
if (states.contains(MaterialState.hovered)) {
return ${componentColor('md.comp.switch.unselected.hover.track')};
}
if (states.contains(MaterialState.focused)) {
return ${componentColor('md.comp.switch.unselected.focus.track')};
}
return ${componentColor('md.comp.switch.unselected.track')};
});
}
@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.switch.selected.pressed.state-layer')};
}
if (states.contains(MaterialState.hovered)) {
return ${componentColor('md.comp.switch.selected.hover.state-layer')};
}
if (states.contains(MaterialState.focused)) {
return ${componentColor('md.comp.switch.selected.focus.state-layer')};
}
return null;
}
if (states.contains(MaterialState.pressed)) {
return ${componentColor('md.comp.switch.unselected.pressed.state-layer')};
}
if (states.contains(MaterialState.hovered)) {
return ${componentColor('md.comp.switch.unselected.hover.state-layer')};
}
if (states.contains(MaterialState.focused)) {
return ${componentColor('md.comp.switch.unselected.focus.state-layer')};
}
return null;
});
}
@override
double get splashRadius => ${tokens['md.comp.switch.state-layer.size']} / 2;
}
class _SwitchConfigM3 with _SwitchConfig {
_SwitchConfigM3(this.context)
: _colors = Theme.of(context).colorScheme;
BuildContext context;
final ColorScheme _colors;
static const double iconSize = ${tokens['md.comp.switch.unselected.icon.size']};
@override
double get activeThumbRadius => ${tokens['md.comp.switch.selected.handle.width']} / 2;
@override
MaterialStateProperty<Color> get iconColor {
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
if (states.contains(MaterialState.selected)) {
return ${componentColor('md.comp.switch.disabled.selected.icon')};
}
return ${componentColor('md.comp.switch.disabled.unselected.icon')};
}
if (states.contains(MaterialState.selected)) {
if (states.contains(MaterialState.pressed)) {
return ${componentColor('md.comp.switch.selected.pressed.icon')};
}
if (states.contains(MaterialState.hovered)) {
return ${componentColor('md.comp.switch.selected.hover.icon')};
}
if (states.contains(MaterialState.focused)) {
return ${componentColor('md.comp.switch.selected.focus.icon')};
}
return ${componentColor('md.comp.switch.selected.icon')};
}
if (states.contains(MaterialState.pressed)) {
return ${componentColor('md.comp.switch.unselected.pressed.icon')};
}
if (states.contains(MaterialState.hovered)) {
return ${componentColor('md.comp.switch.unselected.hover.icon')};
}
if (states.contains(MaterialState.focused)) {
return ${componentColor('md.comp.switch.unselected.focus.icon')};
}
return ${componentColor('md.comp.switch.unselected.icon')};
});
}
@override
double get inactiveThumbRadius => ${tokens['md.comp.switch.unselected.handle.width']} / 2;
@override
double get pressedThumbRadius => ${tokens['md.comp.switch.pressed.handle.width']} / 2;
@override
double get switchHeight => _kSwitchMinSize + 8.0;
@override
double get switchHeightCollapsed => _kSwitchMinSize;
@override
double get switchWidth => trackWidth - 2 * (trackHeight / 2.0) + _kSwitchMinSize;
@override
double get thumbRadiusWithIcon => ${tokens['md.comp.switch.with-icon.handle.width']} / 2;
@override
List<BoxShadow>? get thumbShadow => kElevationToShadow[0];
@override
double get trackHeight => ${tokens['md.comp.switch.track.height']};
@override
MaterialStateProperty<Color?> get trackOutlineColor {
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.selected)) {
return null;
}
if (states.contains(MaterialState.disabled)) {
return ${componentColor('md.comp.switch.disabled.unselected.track.outline')}.withOpacity(${opacity('md.comp.switch.disabled.track.opacity')});
}
return ${componentColor('md.comp.switch.unselected.track.outline')};
});
}
@override
double get trackWidth => ${tokens['md.comp.switch.track.width']};
}
''';
}
// 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.
// Flutter code sample for Switch
import 'package:flutter/material.dart';
void main() => runApp(const SwitchApp());
class SwitchApp extends StatelessWidget {
const SwitchApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(useMaterial3: true, colorSchemeSeed: const Color(0xff6750a4)),
home: Scaffold(
appBar: AppBar(title: const Text('Switch Sample')),
body: const Center(
child: SwitchExample(),
),
),
);
}
}
class SwitchExample extends StatefulWidget {
const SwitchExample({super.key});
@override
State<SwitchExample> createState() => _SwitchExampleState();
}
class _SwitchExampleState extends State<SwitchExample> {
bool light0 = true;
bool light1 = true;
bool light2 = true;
final MaterialStateProperty<Icon?> thumbIcon = MaterialStateProperty.resolveWith<Icon?>((Set<MaterialState> states) {
// Thumb icon when the switch is selected.
if (states.contains(MaterialState.selected)) {
return const Icon(Icons.check);
}
return const Icon(Icons.close);
},
);
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Switch(
value: light0,
onChanged: (bool value) {
setState(() {
light0 = value;
});
},
),
Switch(
thumbIcon: thumbIcon,
value: light1,
onChanged: (bool value) {
setState(() {
light1 = value;
});
},
),
],
);
}
}
......@@ -43,6 +43,7 @@ class SwitchThemeData with Diagnosticable {
this.mouseCursor,
this.overlayColor,
this.splashRadius,
this.thumbIcon,
});
/// {@macro flutter.material.switch.thumbColor}
......@@ -76,6 +77,11 @@ class SwitchThemeData with Diagnosticable {
/// If specified, overrides the default value of [Switch.splashRadius].
final double? splashRadius;
/// {@macro flutter.material.switch.thumbIcon}
///
/// It is overridden by [Switch.thumbIcon].
final MaterialStateProperty<Icon?>? thumbIcon;
/// Creates a copy of this object but with the given fields replaced with the
/// new values.
SwitchThemeData copyWith({
......@@ -85,6 +91,7 @@ class SwitchThemeData with Diagnosticable {
MaterialStateProperty<MouseCursor?>? mouseCursor,
MaterialStateProperty<Color?>? overlayColor,
double? splashRadius,
MaterialStateProperty<Icon?>? thumbIcon,
}) {
return SwitchThemeData(
thumbColor: thumbColor ?? this.thumbColor,
......@@ -93,6 +100,7 @@ class SwitchThemeData with Diagnosticable {
mouseCursor: mouseCursor ?? this.mouseCursor,
overlayColor: overlayColor ?? this.overlayColor,
splashRadius: splashRadius ?? this.splashRadius,
thumbIcon: thumbIcon ?? this.thumbIcon,
);
}
......@@ -107,6 +115,7 @@ class SwitchThemeData with Diagnosticable {
mouseCursor: t < 0.5 ? a?.mouseCursor : b?.mouseCursor,
overlayColor: MaterialStateProperty.lerp<Color?>(a?.overlayColor, b?.overlayColor, t, Color.lerp),
splashRadius: lerpDouble(a?.splashRadius, b?.splashRadius, t),
thumbIcon: t < 0.5 ? a?.thumbIcon : b?.thumbIcon,
);
}
......@@ -118,6 +127,7 @@ class SwitchThemeData with Diagnosticable {
mouseCursor,
overlayColor,
splashRadius,
thumbIcon,
);
@override
......@@ -134,7 +144,8 @@ class SwitchThemeData with Diagnosticable {
&& other.materialTapTargetSize == materialTapTargetSize
&& other.mouseCursor == mouseCursor
&& other.overlayColor == overlayColor
&& other.splashRadius == splashRadius;
&& other.splashRadius == splashRadius
&& other.thumbIcon == thumbIcon;
}
@override
......@@ -146,6 +157,7 @@ class SwitchThemeData with Diagnosticable {
properties.add(DiagnosticsProperty<MaterialStateProperty<MouseCursor?>>('mouseCursor', mouseCursor, defaultValue: null));
properties.add(DiagnosticsProperty<MaterialStateProperty<Color?>>('overlayColor', overlayColor, defaultValue: null));
properties.add(DoubleProperty('splashRadius', splashRadius, defaultValue: null));
properties.add(DiagnosticsProperty<MaterialStateProperty<Icon?>>('thumbIcon', thumbIcon, defaultValue: null));
}
}
......
......@@ -1252,7 +1252,7 @@ class ThemeData with Diagnosticable {
/// * Typography: `typography` (see table above)
///
/// ### Components
/// * Common buttons: [ElevatedButton], [FilledButton], [OutlinedButton], [TextButton]
/// * Common buttons: [ElevatedButton], [FilledButton], [OutlinedButton], [TextButton], [IconButton]
/// * FAB: [FloatingActionButton]
/// * Extended FAB: [FloatingActionButton.extended]
/// * Cards: [Card]
......@@ -1266,6 +1266,7 @@ class ThemeData with Diagnosticable {
/// * Lists: [ListTile]
/// * Navigation bar: [NavigationBar] (new, replacing [BottomNavigationBar])
/// * [Navigation rail](https://m3.material.io/components/navigation-rail): [NavigationRail]
/// * Switch: [Switch]
/// * Top app bar: [AppBar]
///
/// In addition, this flag enables features introduced in Android 12.
......
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