From c1c2513ac97740c447fdd75537489e7d6784e612 Mon Sep 17 00:00:00 2001 From: Qun Cheng <36861262+QuncCccccc@users.noreply.github.com> Date: Fri, 5 May 2023 13:34:08 -0700 Subject: [PATCH] Add `Switch.trackOutlineWidth` property (#125848) --- .../gen_defaults/lib/switch_template.dart | 3 + packages/flutter/lib/src/material/switch.dart | 85 +++++++++-- .../lib/src/material/switch_theme.dart | 12 ++ .../flutter/test/material/switch_test.dart | 135 ++++++++++++++++++ .../test/material/switch_theme_test.dart | 62 ++++++-- 5 files changed, 274 insertions(+), 23 deletions(-) diff --git a/dev/tools/gen_defaults/lib/switch_template.dart b/dev/tools/gen_defaults/lib/switch_template.dart index 0ac2abee78..95a4da74a7 100644 --- a/dev/tools/gen_defaults/lib/switch_template.dart +++ b/dev/tools/gen_defaults/lib/switch_template.dart @@ -126,6 +126,9 @@ class _${blockName}DefaultsM3 extends SwitchThemeData { }); } + @override + MaterialStatePropertyAll get trackOutlineWidth => const MaterialStatePropertyAll(${tokens['md.comp.switch.track.outline.width']}); + @override double get splashRadius => ${tokens['md.comp.switch.state-layer.size']} / 2; } diff --git a/packages/flutter/lib/src/material/switch.dart b/packages/flutter/lib/src/material/switch.dart index 55ec9ceab7..9d5d662451 100644 --- a/packages/flutter/lib/src/material/switch.dart +++ b/packages/flutter/lib/src/material/switch.dart @@ -106,6 +106,7 @@ class Switch extends StatelessWidget { this.thumbColor, this.trackColor, this.trackOutlineColor, + this.trackOutlineWidth, this.thumbIcon, this.materialTapTargetSize, this.dragStartBehavior = DragStartBehavior.start, @@ -132,7 +133,7 @@ class Switch extends StatelessWidget { /// design [Switch]. /// /// If a [CupertinoSwitch] is created, the following parameters are ignored: - /// [activeTrackColor], [inactiveThumbColor], [inactiveTrackColor], + /// [activeTrackColor], [inactiveThumbColor], [inactiveTrackColor], [trackOutlineWidth] /// [activeThumbImage], [onActiveThumbImageError], [inactiveThumbImage], /// [onInactiveThumbImageError], [materialTapTargetSize]. /// @@ -153,6 +154,7 @@ class Switch extends StatelessWidget { this.thumbColor, this.trackColor, this.trackOutlineColor, + this.trackOutlineWidth, this.thumbIcon, this.dragStartBehavior = DragStartBehavior.start, this.mouseCursor, @@ -286,7 +288,7 @@ class Switch extends StatelessWidget { /// ```dart /// Switch( /// value: true, - /// onChanged: (_) => true, + /// onChanged: (bool value) { }, /// thumbColor: MaterialStateProperty.resolveWith((Set states) { /// if (states.contains(MaterialState.disabled)) { /// return Colors.orange.withOpacity(.48); @@ -327,7 +329,7 @@ class Switch extends StatelessWidget { /// ```dart /// Switch( /// value: true, - /// onChanged: (_) => true, + /// onChanged: (bool value) { }, /// thumbColor: MaterialStateProperty.resolveWith((Set states) { /// if (states.contains(MaterialState.disabled)) { /// return Colors.orange.withOpacity(.48); @@ -368,7 +370,7 @@ class Switch extends StatelessWidget { /// ```dart /// Switch( /// value: true, - /// onChanged: (_) => true, + /// onChanged: (bool value) { }, /// trackOutlineColor: MaterialStateProperty.resolveWith((Set states) { /// if (states.contains(MaterialState.disabled)) { /// return Colors.orange.withOpacity(.48); @@ -385,6 +387,38 @@ class Switch extends StatelessWidget { /// the [Switch] track has no outline by default. final MaterialStateProperty? trackOutlineColor; + /// {@template flutter.material.switch.trackOutlineWidth} + /// The outline width of this [Switch]'s track. + /// + /// Resolved in the following states: + /// * [MaterialState.selected]. + /// * [MaterialState.hovered]. + /// * [MaterialState.focused]. + /// * [MaterialState.disabled]. + /// + /// {@tool snippet} + /// This example resolves the [trackOutlineWidth] based on the current + /// [MaterialState] of the [Switch], providing a different outline width when it is + /// [MaterialState.disabled]. + /// + /// ```dart + /// Switch( + /// value: true, + /// onChanged: (bool value) { }, + /// trackOutlineWidth: MaterialStateProperty.resolveWith((Set states) { + /// if (states.contains(MaterialState.disabled)) { + /// return 5.0; + /// } + /// return null; // Use the default width. + /// }), + /// ) + /// ``` + /// {@end-tool} + /// {@endtemplate} + /// + /// Defaults to 2.0. + final MaterialStateProperty? trackOutlineWidth; + /// {@template flutter.material.switch.thumbIcon} /// The icon to use on the thumb of this switch /// @@ -402,7 +436,7 @@ class Switch extends StatelessWidget { /// ```dart /// Switch( /// value: true, - /// onChanged: (_) => true, + /// onChanged: (bool value) { }, /// thumbIcon: MaterialStateProperty.resolveWith((Set states) { /// if (states.contains(MaterialState.disabled)) { /// return const Icon(Icons.close); @@ -572,6 +606,7 @@ class Switch extends StatelessWidget { thumbColor: thumbColor, trackColor: trackColor, trackOutlineColor: trackOutlineColor, + trackOutlineWidth: trackOutlineWidth, thumbIcon: thumbIcon, materialTapTargetSize: materialTapTargetSize, dragStartBehavior: dragStartBehavior, @@ -632,6 +667,7 @@ class _MaterialSwitch extends StatefulWidget { this.thumbColor, this.trackColor, this.trackOutlineColor, + this.trackOutlineWidth, this.thumbIcon, this.materialTapTargetSize, this.dragStartBehavior = DragStartBehavior.start, @@ -659,6 +695,7 @@ class _MaterialSwitch extends StatefulWidget { final MaterialStateProperty? thumbColor; final MaterialStateProperty? trackColor; final MaterialStateProperty? trackOutlineColor; + final MaterialStateProperty? trackOutlineWidth; final MaterialStateProperty? thumbIcon; final MaterialTapTargetSize? materialTapTargetSize; final DragStartBehavior dragStartBehavior; @@ -821,6 +858,9 @@ class _MaterialSwitchState extends State<_MaterialSwitch> with TickerProviderSta final Color effectiveActiveTrackOutlineColor = widget.trackOutlineColor?.resolve(activeStates) ?? switchTheme.trackOutlineColor?.resolve(activeStates) ?? Colors.transparent; + final double? effectiveActiveTrackOutlineWidth = widget.trackOutlineWidth?.resolve(activeStates) + ?? switchTheme.trackOutlineWidth?.resolve(activeStates) + ?? defaults.trackOutlineWidth?.resolve(activeStates); final Color effectiveInactiveTrackColor = widget.trackColor?.resolve(inactiveStates) ?? _widgetTrackColor.resolve(inactiveStates) @@ -829,6 +869,9 @@ class _MaterialSwitchState extends State<_MaterialSwitch> with TickerProviderSta final Color? effectiveInactiveTrackOutlineColor = widget.trackOutlineColor?.resolve(inactiveStates) ?? switchTheme.trackOutlineColor?.resolve(inactiveStates) ?? defaults.trackOutlineColor?.resolve(inactiveStates); + final double? effectiveInactiveTrackOutlineWidth = widget.trackOutlineWidth?.resolve(inactiveStates) + ?? switchTheme.trackOutlineWidth?.resolve(inactiveStates) + ?? defaults.trackOutlineWidth?.resolve(inactiveStates); final Icon? effectiveActiveIcon = widget.thumbIcon?.resolve(activeStates) ?? switchTheme.thumbIcon?.resolve(activeStates); @@ -918,8 +961,10 @@ class _MaterialSwitchState extends State<_MaterialSwitch> with TickerProviderSta ..onInactiveThumbImageError = widget.onInactiveThumbImageError ..activeTrackColor = effectiveActiveTrackColor ..activeTrackOutlineColor = effectiveActiveTrackOutlineColor + ..activeTrackOutlineWidth = effectiveActiveTrackOutlineWidth ..inactiveTrackColor = effectiveInactiveTrackColor ..inactiveTrackOutlineColor = effectiveInactiveTrackOutlineColor + ..inactiveTrackOutlineWidth = effectiveInactiveTrackOutlineWidth ..configuration = createLocalImageConfiguration(context) ..isInteractive = isInteractive ..trackInnerLength = _trackInnerLength @@ -1169,6 +1214,26 @@ class _SwitchPainter extends ToggleablePainter { notifyListeners(); } + double? get activeTrackOutlineWidth => _activeTrackOutlineWidth; + double? _activeTrackOutlineWidth; + set activeTrackOutlineWidth(double? value) { + if (value == _activeTrackOutlineWidth) { + return; + } + _activeTrackOutlineWidth = value; + notifyListeners(); + } + + double? get inactiveTrackOutlineWidth => _inactiveTrackOutlineWidth; + double? _inactiveTrackOutlineWidth; + set inactiveTrackOutlineWidth(double? value) { + if (value == _inactiveTrackOutlineWidth) { + return; + } + _inactiveTrackOutlineWidth = value; + notifyListeners(); + } + Color get inactiveTrackColor => _inactiveTrackColor!; Color? _inactiveTrackColor; set inactiveTrackColor(Color value) { @@ -1366,6 +1431,7 @@ class _SwitchPainter extends ToggleablePainter { final Color trackColor = Color.lerp(inactiveTrackColor, activeTrackColor, colorValue)!; final Color? trackOutlineColor = inactiveTrackOutlineColor == null ? null : Color.lerp(inactiveTrackOutlineColor, activeTrackOutlineColor, colorValue); + final double? trackOutlineWidth = lerpDouble(inactiveTrackOutlineWidth, activeTrackOutlineWidth, colorValue); Color lerpedThumbColor; if (!reaction.isDismissed) { lerpedThumbColor = Color.lerp(inactivePressedColor, activePressedColor, colorValue)!; @@ -1395,7 +1461,7 @@ class _SwitchPainter extends ToggleablePainter { final Offset thumbPaintOffset = _computeThumbPaintOffset(trackPaintOffset, thumbSize, visualPosition); final Offset radialReactionOrigin = Offset(thumbPaintOffset.dx + thumbSize.height / 2, size.height / 2); - _paintTrackWith(canvas, paint, trackPaintOffset, trackOutlineColor); + _paintTrackWith(canvas, paint, trackPaintOffset, trackOutlineColor, trackOutlineWidth); paintRadialReaction(canvas: canvas, origin: radialReactionOrigin); _paintThumbWith( thumbPaintOffset, @@ -1433,7 +1499,7 @@ class _SwitchPainter extends ToggleablePainter { return Offset(thumbHorizontalOffset, thumbVerticalOffset); } - void _paintTrackWith(Canvas canvas, Paint paint, Offset trackPaintOffset, Color? trackOutlineColor) { + void _paintTrackWith(Canvas canvas, Paint paint, Offset trackPaintOffset, Color? trackOutlineColor, double? trackOutlineWidth) { final Rect trackRect = Rect.fromLTWH( trackPaintOffset.dx, trackPaintOffset.dy, @@ -1462,7 +1528,7 @@ class _SwitchPainter extends ToggleablePainter { ); final Paint outlinePaint = Paint() ..style = PaintingStyle.stroke - ..strokeWidth = 2 + ..strokeWidth = trackOutlineWidth ?? 2.0 ..color = trackOutlineColor; canvas.drawRRect(outlineTrackRRect, outlinePaint); } @@ -1808,6 +1874,9 @@ class _SwitchDefaultsM3 extends SwitchThemeData { }); } + @override + MaterialStatePropertyAll get trackOutlineWidth => const MaterialStatePropertyAll(2.0); + @override double get splashRadius => 40.0 / 2; } diff --git a/packages/flutter/lib/src/material/switch_theme.dart b/packages/flutter/lib/src/material/switch_theme.dart index ca3e045020..e0753cf884 100644 --- a/packages/flutter/lib/src/material/switch_theme.dart +++ b/packages/flutter/lib/src/material/switch_theme.dart @@ -40,6 +40,7 @@ class SwitchThemeData with Diagnosticable { this.thumbColor, this.trackColor, this.trackOutlineColor, + this.trackOutlineWidth, this.materialTapTargetSize, this.mouseCursor, this.overlayColor, @@ -62,6 +63,11 @@ class SwitchThemeData with Diagnosticable { /// If specified, overrides the default value of [Switch.trackOutlineColor]. final MaterialStateProperty? trackOutlineColor; + /// {@macro flutter.material.switch.trackOutlineWidth} + /// + /// If specified, overrides the default value of [Switch.trackOutlineWidth]. + final MaterialStateProperty? trackOutlineWidth; + /// {@macro flutter.material.switch.materialTapTargetSize} /// /// If specified, overrides the default value of @@ -94,6 +100,7 @@ class SwitchThemeData with Diagnosticable { MaterialStateProperty? thumbColor, MaterialStateProperty? trackColor, MaterialStateProperty? trackOutlineColor, + MaterialStateProperty? trackOutlineWidth, MaterialTapTargetSize? materialTapTargetSize, MaterialStateProperty? mouseCursor, MaterialStateProperty? overlayColor, @@ -104,6 +111,7 @@ class SwitchThemeData with Diagnosticable { thumbColor: thumbColor ?? this.thumbColor, trackColor: trackColor ?? this.trackColor, trackOutlineColor: trackOutlineColor ?? this.trackOutlineColor, + trackOutlineWidth: trackOutlineWidth ?? this.trackOutlineWidth, materialTapTargetSize: materialTapTargetSize ?? this.materialTapTargetSize, mouseCursor: mouseCursor ?? this.mouseCursor, overlayColor: overlayColor ?? this.overlayColor, @@ -123,6 +131,7 @@ class SwitchThemeData with Diagnosticable { thumbColor: MaterialStateProperty.lerp(a?.thumbColor, b?.thumbColor, t, Color.lerp), trackColor: MaterialStateProperty.lerp(a?.trackColor, b?.trackColor, t, Color.lerp), trackOutlineColor: MaterialStateProperty.lerp(a?.trackOutlineColor, b?.trackOutlineColor, t, Color.lerp), + trackOutlineWidth: MaterialStateProperty.lerp(a?.trackOutlineWidth, b?.trackOutlineWidth, t, lerpDouble), materialTapTargetSize: t < 0.5 ? a?.materialTapTargetSize : b?.materialTapTargetSize, mouseCursor: t < 0.5 ? a?.mouseCursor : b?.mouseCursor, overlayColor: MaterialStateProperty.lerp(a?.overlayColor, b?.overlayColor, t, Color.lerp), @@ -136,6 +145,7 @@ class SwitchThemeData with Diagnosticable { thumbColor, trackColor, trackOutlineColor, + trackOutlineWidth, materialTapTargetSize, mouseCursor, overlayColor, @@ -155,6 +165,7 @@ class SwitchThemeData with Diagnosticable { && other.thumbColor == thumbColor && other.trackColor == trackColor && other.trackOutlineColor == trackOutlineColor + && other.trackOutlineWidth == trackOutlineWidth && other.materialTapTargetSize == materialTapTargetSize && other.mouseCursor == mouseCursor && other.overlayColor == overlayColor @@ -168,6 +179,7 @@ class SwitchThemeData with Diagnosticable { properties.add(DiagnosticsProperty>('thumbColor', thumbColor, defaultValue: null)); properties.add(DiagnosticsProperty>('trackColor', trackColor, defaultValue: null)); properties.add(DiagnosticsProperty>('trackOutlineColor', trackOutlineColor, defaultValue: null)); + properties.add(DiagnosticsProperty>('trackOutlineWidth', trackOutlineWidth, defaultValue: null)); properties.add(DiagnosticsProperty('materialTapTargetSize', materialTapTargetSize, defaultValue: null)); properties.add(DiagnosticsProperty>('mouseCursor', mouseCursor, defaultValue: null)); properties.add(DiagnosticsProperty>('overlayColor', overlayColor, defaultValue: null)); diff --git a/packages/flutter/test/material/switch_test.dart b/packages/flutter/test/material/switch_test.dart index 4e0d61a8bb..0c10a7bc15 100644 --- a/packages/flutter/test/material/switch_test.dart +++ b/packages/flutter/test/material/switch_test.dart @@ -2967,6 +2967,141 @@ void main() { ); }); + testWidgets('Track outline width resolves in active/enabled states', (WidgetTester tester) async { + const double activeEnabledTrackOutlineWidth = 1.0; + const double activeDisabledTrackOutlineWidth = 2.0; + const double inactiveEnabledTrackOutlineWidth = 3.0; + const double inactiveDisabledTrackOutlineWidth = 4.0; + + double getTrackOutlineWidth(Set states) { + if (states.contains(MaterialState.disabled)) { + if (states.contains(MaterialState.selected)) { + return activeDisabledTrackOutlineWidth; + } + return inactiveDisabledTrackOutlineWidth; + } + if (states.contains(MaterialState.selected)) { + return activeEnabledTrackOutlineWidth; + } + return inactiveEnabledTrackOutlineWidth; + } + + final MaterialStateProperty trackOutlineWidth = MaterialStateProperty.resolveWith(getTrackOutlineWidth); + + Widget buildSwitch({required bool enabled, required bool active}) { + return MaterialApp( + theme: ThemeData(useMaterial3: true), + home: Material( + child: Center( + child: Switch( + trackOutlineWidth: trackOutlineWidth, + value: active, + onChanged: enabled ? (_) { } : null, + ), + ), + ), + ); + } + + await tester.pumpWidget(buildSwitch(enabled: false, active: false)); + + expect( + Material.of(tester.element(find.byType(Switch))), + paints..rrect(style: PaintingStyle.fill) + ..rrect(strokeWidth: inactiveDisabledTrackOutlineWidth, style: PaintingStyle.stroke), + reason: 'Inactive disabled switch track outline width should be 4.0', + ); + + await tester.pumpWidget(buildSwitch(enabled: false, active: true)); + await tester.pumpAndSettle(); + + expect( + Material.of(tester.element(find.byType(Switch))), + paints..rrect(style: PaintingStyle.fill) + ..rrect(strokeWidth: activeDisabledTrackOutlineWidth, style: PaintingStyle.stroke), + reason: 'Active disabled switch track outline width should be 2.0', + ); + + await tester.pumpWidget(buildSwitch(enabled: true, active: false)); + await tester.pumpAndSettle(); + + expect( + Material.of(tester.element(find.byType(Switch))), + paints..rrect(style: PaintingStyle.fill) + ..rrect(strokeWidth: inactiveEnabledTrackOutlineWidth, style: PaintingStyle.stroke), + reason: 'Inactive enabled switch track outline width should be 3.0', + ); + + await tester.pumpWidget(buildSwitch(enabled: true, active: true)); + await tester.pumpAndSettle(); + + expect( + Material.of(tester.element(find.byType(Switch))), + paints..rrect(style: PaintingStyle.fill) + ..rrect(strokeWidth: activeEnabledTrackOutlineWidth, style: PaintingStyle.stroke), + reason: 'Active enabled switch track outline width should be 1.0', + ); + }); + + testWidgets('Switch track outline width resolves in hovered/focused states', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(debugLabel: 'Switch'); + tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; + const double hoveredTrackOutlineWidth = 4.0; + const double focusedTrackOutlineWidth = 6.0; + + double getTrackOutlineWidth(Set states) { + if (states.contains(MaterialState.hovered)) { + return hoveredTrackOutlineWidth; + } + if (states.contains(MaterialState.focused)) { + return focusedTrackOutlineWidth; + } + return 8.0; + } + + final MaterialStateProperty trackOutlineWidth = MaterialStateProperty.resolveWith(getTrackOutlineWidth); + + Widget buildSwitch() { + return MaterialApp( + theme: ThemeData(useMaterial3: true), + home: Material( + child: Center( + child: Switch( + focusNode: focusNode, + autofocus: true, + value: true, + trackOutlineWidth: trackOutlineWidth, + onChanged: (_) { }, + ), + ), + ), + ); + } + + await tester.pumpWidget(buildSwitch()); + await tester.pumpAndSettle(); + expect(focusNode.hasPrimaryFocus, isTrue); + expect( + Material.of(tester.element(find.byType(Switch))), + paints..rrect(style: PaintingStyle.fill) + ..rrect(strokeWidth: focusedTrackOutlineWidth, style: PaintingStyle.stroke), + reason: 'Active enabled switch track outline width should be 6.0', + ); + + // Start hovering + final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); + await gesture.addPointer(); + await gesture.moveTo(tester.getCenter(find.byType(Switch))); + await tester.pumpAndSettle(); + + expect( + Material.of(tester.element(find.byType(Switch))), + paints..rrect(style: PaintingStyle.fill) + ..rrect(strokeWidth: hoveredTrackOutlineWidth, style: PaintingStyle.stroke), + reason: 'Active enabled switch track outline width should be 4.0', + ); + }); + testWidgets('Switch thumb color is blended against surface color - M3', (WidgetTester tester) async { final Color activeDisabledThumbColor = Colors.blue.withOpacity(.60); final ThemeData theme = ThemeData.light(useMaterial3: true); diff --git a/packages/flutter/test/material/switch_theme_test.dart b/packages/flutter/test/material/switch_theme_test.dart index d7ae667716..cc7e6b3645 100644 --- a/packages/flutter/test/material/switch_theme_test.dart +++ b/packages/flutter/test/material/switch_theme_test.dart @@ -25,6 +25,7 @@ void main() { expect(themeData.thumbColor, null); expect(themeData.trackColor, null); expect(themeData.trackOutlineColor, null); + expect(themeData.trackOutlineWidth, null); expect(themeData.mouseCursor, null); expect(themeData.materialTapTargetSize, null); expect(themeData.overlayColor, null); @@ -35,6 +36,7 @@ void main() { expect(theme.data.thumbColor, null); expect(theme.data.trackColor, null); expect(theme.data.trackOutlineColor, null); + expect(theme.data.trackOutlineWidth, null); expect(theme.data.mouseCursor, null); expect(theme.data.materialTapTargetSize, null); expect(theme.data.overlayColor, null); @@ -60,6 +62,7 @@ void main() { thumbColor: MaterialStatePropertyAll(Color(0xfffffff0)), trackColor: MaterialStatePropertyAll(Color(0xfffffff1)), trackOutlineColor: MaterialStatePropertyAll(Color(0xfffffff3)), + trackOutlineWidth: MaterialStatePropertyAll(6.0), mouseCursor: MaterialStatePropertyAll(SystemMouseCursors.click), materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, overlayColor: MaterialStatePropertyAll(Color(0xfffffff2)), @@ -75,11 +78,12 @@ void main() { expect(description[0], 'thumbColor: MaterialStatePropertyAll(Color(0xfffffff0))'); expect(description[1], 'trackColor: MaterialStatePropertyAll(Color(0xfffffff1))'); expect(description[2], 'trackOutlineColor: MaterialStatePropertyAll(Color(0xfffffff3))'); - expect(description[3], 'materialTapTargetSize: MaterialTapTargetSize.shrinkWrap'); - expect(description[4], 'mouseCursor: MaterialStatePropertyAll(SystemMouseCursor(click))'); - expect(description[5], 'overlayColor: MaterialStatePropertyAll(Color(0xfffffff2))'); - expect(description[6], 'splashRadius: 1.0'); - expect(description[7], 'thumbIcon: MaterialStatePropertyAll(Icon(IconData(U+0007B)))'); + expect(description[3], 'trackOutlineWidth: MaterialStatePropertyAll(6.0)'); + expect(description[4], 'materialTapTargetSize: MaterialTapTargetSize.shrinkWrap'); + expect(description[5], 'mouseCursor: MaterialStatePropertyAll(SystemMouseCursor(click))'); + expect(description[6], 'overlayColor: MaterialStatePropertyAll(Color(0xfffffff2))'); + expect(description[7], 'splashRadius: 1.0'); + expect(description[8], 'thumbIcon: MaterialStatePropertyAll(Icon(IconData(U+0007B)))'); }); testWidgets('Switch is themeable', (WidgetTester tester) async { @@ -91,6 +95,8 @@ void main() { const Color selectedTrackColor = Color(0xfffffff3); const Color defaultTrackOutlineColor = Color(0xfffffff4); const Color selectedTrackOutlineColor = Color(0xfffffff5); + const double defaultTrackOutlineWidth = 3.0; + const double selectedTrackOutlineWidth = 6.0; const MouseCursor mouseCursor = SystemMouseCursors.text; const MaterialTapTargetSize materialTapTargetSize = MaterialTapTargetSize.shrinkWrap; const Color focusOverlayColor = Color(0xfffffff4); @@ -119,6 +125,12 @@ void main() { } return defaultTrackOutlineColor; }), + trackOutlineWidth: MaterialStateProperty.resolveWith((Set states) { + if (states.contains(MaterialState.selected)) { + return selectedTrackOutlineWidth; + } + return defaultTrackOutlineWidth; + }), mouseCursor: const MaterialStatePropertyAll(mouseCursor), materialTapTargetSize: materialTapTargetSize, overlayColor: MaterialStateProperty.resolveWith((Set states) { @@ -162,13 +174,13 @@ void main() { material3 ? (paints ..rrect(color: defaultTrackColor) - ..rrect(color: defaultTrackOutlineColor) + ..rrect(color: defaultTrackOutlineColor, strokeWidth: defaultTrackOutlineWidth) ..rrect(color: defaultThumbColor) ..paragraph() ) : (paints ..rrect(color: defaultTrackColor) - ..rrect(color: defaultTrackOutlineColor) + ..rrect(color: defaultTrackOutlineColor, strokeWidth: defaultTrackOutlineWidth) ..rrect() ..rrect() ..rrect() @@ -186,11 +198,11 @@ void main() { material3 ? (paints ..rrect(color: selectedTrackColor) - ..rrect(color: selectedTrackOutlineColor) + ..rrect(color: selectedTrackOutlineColor, strokeWidth: selectedTrackOutlineWidth) ..rrect(color: selectedThumbColor)..paragraph()) : (paints ..rrect(color: selectedTrackColor) - ..rrect(color: selectedTrackOutlineColor) + ..rrect(color: selectedTrackOutlineColor, strokeWidth: selectedTrackOutlineWidth) ..rrect() ..rrect() ..rrect() @@ -219,6 +231,8 @@ void main() { const Color themeSelectedTrackColor = Color(0xfffffff3); const Color themeDefaultOutlineColor = Color(0xfffffff6); const Color themeSelectedOutlineColor = Color(0xfffffff7); + const double themeDefaultOutlineWidth = 5.0; + const double themeSelectedOutlineWidth = 7.0; const MouseCursor themeMouseCursor = SystemMouseCursors.click; const MaterialTapTargetSize themeMaterialTapTargetSize = MaterialTapTargetSize.padded; const Color themeFocusOverlayColor = Color(0xfffffff4); @@ -231,6 +245,8 @@ void main() { const Color selectedTrackColor = Color(0xffffff3f); const Color defaultOutlineColor = Color(0xffffff6f); const Color selectedOutlineColor = Color(0xffffff7f); + const double defaultOutlineWidth = 6.0; + const double selectedOutlineWidth = 8.0; const MouseCursor mouseCursor = SystemMouseCursors.text; const MaterialTapTargetSize materialTapTargetSize = MaterialTapTargetSize.shrinkWrap; const Color focusColor = Color(0xffffff4f); @@ -257,6 +273,12 @@ void main() { } return themeDefaultOutlineColor; }), + trackOutlineWidth: MaterialStateProperty.resolveWith((Set states) { + if (states.contains(MaterialState.selected)) { + return themeSelectedOutlineWidth; + } + return themeDefaultOutlineWidth; + }), mouseCursor: const MaterialStatePropertyAll(themeMouseCursor), materialTapTargetSize: themeMaterialTapTargetSize, overlayColor: MaterialStateProperty.resolveWith((Set states) { @@ -305,6 +327,12 @@ void main() { } return defaultOutlineColor; }), + trackOutlineWidth: MaterialStateProperty.resolveWith((Set states) { + if (states.contains(MaterialState.selected)) { + return selectedOutlineWidth; + } + return defaultOutlineWidth; + }), mouseCursor: mouseCursor, materialTapTargetSize: materialTapTargetSize, focusColor: focusColor, @@ -329,11 +357,11 @@ void main() { material3 ? (paints ..rrect(color: defaultTrackColor) - ..rrect(color: defaultOutlineColor) + ..rrect(color: defaultOutlineColor, strokeWidth: defaultOutlineWidth) ..rrect(color: defaultThumbColor)..paragraph(offset: const Offset(12, 16))) : (paints ..rrect(color: defaultTrackColor) - ..rrect(color: defaultOutlineColor) + ..rrect(color: defaultOutlineColor, strokeWidth: defaultOutlineWidth) ..rrect() ..rrect() ..rrect() @@ -349,11 +377,11 @@ void main() { _getSwitchMaterial(tester), material3 ? (paints - ..rrect(color: selectedTrackColor)..rrect(color: selectedOutlineColor) + ..rrect(color: selectedTrackColor)..rrect(color: selectedOutlineColor, strokeWidth: selectedOutlineWidth) ..rrect(color: selectedThumbColor)) : (paints ..rrect(color: selectedTrackColor) - ..rrect(color: selectedOutlineColor) + ..rrect(color: selectedOutlineColor, strokeWidth: selectedOutlineWidth) ..rrect() ..rrect() ..rrect() @@ -534,15 +562,18 @@ void main() { const Color globalThemeThumbColor = Color(0xfffffff1); const Color globalThemeTrackColor = Color(0xfffffff2); const Color globalThemeOutlineColor = Color(0xfffffff3); + const double globalThemeOutlineWidth = 6.0; const Color localThemeThumbColor = Color(0xffff0000); const Color localThemeTrackColor = Color(0xffff0000); const Color localThemeOutlineColor = Color(0xffff0000); + const double localThemeOutlineWidth = 4.0; final ThemeData themeData = ThemeData( switchTheme: const SwitchThemeData( thumbColor: MaterialStatePropertyAll(globalThemeThumbColor), trackColor: MaterialStatePropertyAll(globalThemeTrackColor), trackOutlineColor: MaterialStatePropertyAll(globalThemeOutlineColor), + trackOutlineWidth: MaterialStatePropertyAll(globalThemeOutlineWidth), ), ); final bool material3 = themeData.useMaterial3; @@ -555,6 +586,7 @@ void main() { thumbColor: MaterialStatePropertyAll(localThemeThumbColor), trackColor: MaterialStatePropertyAll(localThemeTrackColor), trackOutlineColor: MaterialStatePropertyAll(localThemeOutlineColor), + trackOutlineWidth: MaterialStatePropertyAll(localThemeOutlineWidth) ), child: Switch( value: selected, @@ -573,11 +605,11 @@ void main() { material3 ? (paints ..rrect(color: localThemeTrackColor) - ..rrect(color: localThemeOutlineColor) + ..rrect(color: localThemeOutlineColor, strokeWidth: localThemeOutlineWidth) ..rrect(color: localThemeThumbColor)) : (paints ..rrect(color: localThemeTrackColor) - ..rrect(color: localThemeOutlineColor) + ..rrect(color: localThemeOutlineColor, strokeWidth: localThemeOutlineWidth) ..rrect() ..rrect() ..rrect()