Fixed the color curve issue (#115188)
This commit is contained in:
parent
436fb4c6bd
commit
244990775a
@ -620,10 +620,16 @@ class _MaterialSwitchState extends State<_MaterialSwitch> with TickerProviderSta
|
||||
// During a drag we may have modified the curve, reset it if its possible
|
||||
// to do without visual discontinuation.
|
||||
if (position.value == 0.0 || position.value == 1.0) {
|
||||
if (Theme.of(context).useMaterial3) {
|
||||
position
|
||||
..curve = Curves.easeOutBack
|
||||
..reverseCurve = Curves.easeOutBack.flipped;
|
||||
} else {
|
||||
position
|
||||
..curve = Curves.easeIn
|
||||
..reverseCurve = Curves.easeOut;
|
||||
}
|
||||
}
|
||||
animateToValue();
|
||||
}
|
||||
}
|
||||
@ -693,7 +699,7 @@ class _MaterialSwitchState extends State<_MaterialSwitch> with TickerProviderSta
|
||||
|
||||
void _handleDragEnd(DragEndDetails details) {
|
||||
if (position.value >= 0.5 != widget.value) {
|
||||
widget.onChanged!(!widget.value);
|
||||
widget.onChanged?.call(!widget.value);
|
||||
// Wait with finishing the animation until widget.value has changed to
|
||||
// !widget.value as part of the widget.onChanged call above.
|
||||
setState(() {
|
||||
@ -709,7 +715,7 @@ class _MaterialSwitchState extends State<_MaterialSwitch> with TickerProviderSta
|
||||
void _handleChanged(bool? value) {
|
||||
assert(value != null);
|
||||
assert(widget.onChanged != null);
|
||||
widget.onChanged!(value!);
|
||||
widget.onChanged?.call(value!);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -727,11 +733,6 @@ class _MaterialSwitchState extends State<_MaterialSwitch> with TickerProviderSta
|
||||
final SwitchThemeData defaults = theme.useMaterial3 ? _SwitchDefaultsM3(context) : _SwitchDefaultsM2(context);
|
||||
|
||||
positionController.duration = Duration(milliseconds: switchConfig.toggleDuration);
|
||||
if (theme.useMaterial3) {
|
||||
position
|
||||
..curve = Curves.easeOutBack
|
||||
..reverseCurve = Curves.easeOutBack.flipped;
|
||||
}
|
||||
|
||||
// Colors need to be resolved in selected and non selected states separately
|
||||
// so that they can be lerped between.
|
||||
@ -780,12 +781,20 @@ class _MaterialSwitchState extends State<_MaterialSwitch> with TickerProviderSta
|
||||
?? defaults.overlayColor!.resolve(hoveredStates)!;
|
||||
|
||||
final Set<MaterialState> activePressedStates = activeStates..add(MaterialState.pressed);
|
||||
final Color effectiveActivePressedThumbColor = widget.thumbColor?.resolve(activePressedStates)
|
||||
?? _widgetThumbColor.resolve(activePressedStates)
|
||||
?? switchTheme.thumbColor?.resolve(activePressedStates)
|
||||
?? defaults.thumbColor!.resolve(activePressedStates)!;
|
||||
final Color effectiveActivePressedOverlayColor = widget.overlayColor?.resolve(activePressedStates)
|
||||
?? switchTheme.overlayColor?.resolve(activePressedStates)
|
||||
?? activeThumbColor?.withAlpha(kRadialReactionAlpha)
|
||||
?? defaults.overlayColor!.resolve(activePressedStates)!;
|
||||
|
||||
final Set<MaterialState> inactivePressedStates = inactiveStates..add(MaterialState.pressed);
|
||||
final Color effectiveInactivePressedThumbColor = widget.thumbColor?.resolve(inactivePressedStates)
|
||||
?? _widgetThumbColor.resolve(inactivePressedStates)
|
||||
?? switchTheme.thumbColor?.resolve(inactivePressedStates)
|
||||
?? defaults.thumbColor!.resolve(inactivePressedStates)!;
|
||||
final Color effectiveInactivePressedOverlayColor = widget.overlayColor?.resolve(inactivePressedStates)
|
||||
?? switchTheme.overlayColor?.resolve(inactivePressedStates)
|
||||
?? inactiveThumbColor?.withAlpha(kRadialReactionAlpha)
|
||||
@ -830,6 +839,8 @@ class _MaterialSwitchState extends State<_MaterialSwitch> with TickerProviderSta
|
||||
..isHovered = states.contains(MaterialState.hovered)
|
||||
..activeColor = effectiveActiveThumbColor
|
||||
..inactiveColor = effectiveInactiveThumbColor
|
||||
..activePressedColor = effectiveActivePressedThumbColor
|
||||
..inactivePressedColor = effectiveInactivePressedThumbColor
|
||||
..activeThumbImage = widget.activeThumbImage
|
||||
..onActiveThumbImageError = widget.onActiveThumbImageError
|
||||
..inactiveThumbImage = widget.inactiveThumbImage
|
||||
@ -926,6 +937,28 @@ class _SwitchPainter extends ToggleablePainter {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Color get activePressedColor => _activePressedColor!;
|
||||
Color? _activePressedColor;
|
||||
set activePressedColor(Color? value) {
|
||||
assert(value != null);
|
||||
if (value == _activePressedColor) {
|
||||
return;
|
||||
}
|
||||
_activePressedColor = value;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Color get inactivePressedColor => _inactivePressedColor!;
|
||||
Color? _inactivePressedColor;
|
||||
set inactivePressedColor(Color? value) {
|
||||
assert(value != null);
|
||||
if (value == _inactivePressedColor) {
|
||||
return;
|
||||
}
|
||||
_inactivePressedColor = value;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
double get activeThumbRadius => _activeThumbRadius!;
|
||||
double? _activeThumbRadius;
|
||||
set activeThumbRadius(double value) {
|
||||
@ -1180,7 +1213,7 @@ class _SwitchPainter extends ToggleablePainter {
|
||||
visualPosition = currentValue;
|
||||
break;
|
||||
}
|
||||
if (reaction.status == AnimationStatus.reverse && _stopPressAnimation == false) {
|
||||
if (reaction.status == AnimationStatus.reverse && !_stopPressAnimation) {
|
||||
_stopPressAnimation = true;
|
||||
} else {
|
||||
_stopPressAnimation = false;
|
||||
@ -1189,7 +1222,7 @@ class _SwitchPainter extends ToggleablePainter {
|
||||
// To get the thumb radius when the press ends, the value can be any number
|
||||
// between activeThumbRadius/inactiveThumbRadius and pressedThumbRadius.
|
||||
if (!_stopPressAnimation) {
|
||||
if (reaction.status == AnimationStatus.completed) {
|
||||
if (reaction.isCompleted) {
|
||||
// This happens when the thumb is dragged instead of being tapped.
|
||||
_pressedInactiveThumbRadius = lerpDouble(inactiveThumbRadius, pressedThumbRadius, reaction.value);
|
||||
_pressedActiveThumbRadius = lerpDouble(activeThumbRadius, pressedThumbRadius, reaction.value);
|
||||
@ -1248,10 +1281,10 @@ class _SwitchPainter extends ToggleablePainter {
|
||||
}
|
||||
|
||||
Size thumbSize;
|
||||
if (reaction.status == AnimationStatus.completed) {
|
||||
if (reaction.isCompleted) {
|
||||
thumbSize = Size.fromRadius(pressedThumbRadius);
|
||||
} else {
|
||||
if (position.status == AnimationStatus.dismissed || position.status == AnimationStatus.forward) {
|
||||
if (position.isDismissed || position.status == AnimationStatus.forward) {
|
||||
thumbSize = thumbSizeAnimation(true).value;
|
||||
} else {
|
||||
thumbSize = thumbSizeAnimation(false).value;
|
||||
@ -1262,10 +1295,21 @@ class _SwitchPainter extends ToggleablePainter {
|
||||
final double inset = thumbOffset == null ? 0 : 1.0 - (currentValue - thumbOffset!).abs() * 2.0;
|
||||
thumbSize = Size(thumbSize.width - inset, thumbSize.height - inset);
|
||||
|
||||
final Color trackColor = Color.lerp(inactiveTrackColor, activeTrackColor, currentValue)!;
|
||||
final double colorValue = CurvedAnimation(parent: positionController, curve: Curves.easeOut, reverseCurve: Curves.easeIn).value;
|
||||
final Color trackColor = Color.lerp(inactiveTrackColor, activeTrackColor, colorValue)!;
|
||||
final Color? trackOutlineColor = inactiveTrackOutlineColor == null ? null
|
||||
: Color.lerp(inactiveTrackOutlineColor, Colors.transparent, currentValue);
|
||||
final Color lerpedThumbColor = Color.lerp(inactiveColor, activeColor, currentValue)!;
|
||||
: Color.lerp(inactiveTrackOutlineColor, Colors.transparent, colorValue);
|
||||
Color lerpedThumbColor;
|
||||
if (!reaction.isDismissed) {
|
||||
lerpedThumbColor = Color.lerp(inactivePressedColor, activePressedColor, colorValue)!;
|
||||
} else if (positionController.status == AnimationStatus.forward) {
|
||||
lerpedThumbColor = Color.lerp(inactivePressedColor, activeColor, colorValue)!;
|
||||
} else if (positionController.status == AnimationStatus.reverse) {
|
||||
lerpedThumbColor = Color.lerp(inactiveColor, activePressedColor, colorValue)!;
|
||||
} else {
|
||||
lerpedThumbColor = Color.lerp(inactiveColor, activeColor, colorValue)!;
|
||||
}
|
||||
|
||||
// Blend the thumb color against a `surfaceColor` background in case the
|
||||
// thumbColor is not opaque. This way we do not see through the thumb to the
|
||||
// track underneath.
|
||||
@ -1289,7 +1333,7 @@ class _SwitchPainter extends ToggleablePainter {
|
||||
_paintThumbWith(
|
||||
thumbPaintOffset,
|
||||
canvas,
|
||||
currentValue,
|
||||
colorValue,
|
||||
thumbColor,
|
||||
thumbImage,
|
||||
thumbErrorListener,
|
||||
@ -1381,7 +1425,7 @@ class _SwitchPainter extends ToggleablePainter {
|
||||
|
||||
thumbPainter.paint(
|
||||
canvas,
|
||||
thumbPaintOffset + Offset(0, inset),
|
||||
thumbPaintOffset,
|
||||
configuration.copyWith(size: thumbSize),
|
||||
);
|
||||
|
||||
|
@ -2438,6 +2438,89 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Switch thumb shows correct pressed color - M3', (WidgetTester tester) async {
|
||||
final ThemeData themeData = ThemeData(useMaterial3: true);
|
||||
final ColorScheme colors = themeData.colorScheme;
|
||||
Widget buildApp({bool enabled = true, bool value = true}) {
|
||||
return MaterialApp(
|
||||
theme: themeData,
|
||||
home: Material(
|
||||
child: Center(
|
||||
child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
|
||||
return Switch(
|
||||
value: value,
|
||||
onChanged: enabled ? (bool newValue) {
|
||||
setState(() {
|
||||
value = newValue;
|
||||
});
|
||||
} : null,
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(buildApp());
|
||||
await tester.press(find.byType(Switch));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(Material.of(tester.element(find.byType(Switch))),
|
||||
paints..rrect(
|
||||
color: colors.primary, // track color
|
||||
style: PaintingStyle.fill,
|
||||
)..rrect(
|
||||
color: Colors.transparent, // track outline color
|
||||
style: PaintingStyle.stroke,
|
||||
)..rrect(color: colors.primaryContainer, rrect: RRect.fromLTRBR(26.0, 10.0, 54.0, 38.0, const Radius.circular(14.0))),
|
||||
);
|
||||
|
||||
await tester.pumpWidget(Container());
|
||||
await tester.pumpWidget(buildApp(value: false));
|
||||
await tester.press(find.byType(Switch));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(Material.of(tester.element(find.byType(Switch))),
|
||||
paints..rrect(
|
||||
color: colors.surfaceVariant, // track color
|
||||
style: PaintingStyle.fill
|
||||
)..rrect(
|
||||
color: colors.outline, // track outline color
|
||||
style: PaintingStyle.stroke,
|
||||
)..rrect(color: colors.onSurfaceVariant),
|
||||
);
|
||||
|
||||
await tester.pumpWidget(Container());
|
||||
await tester.pumpWidget(buildApp(enabled: false));
|
||||
await tester.press(find.byType(Switch));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(Material.of(tester.element(find.byType(Switch))),
|
||||
paints..rrect(
|
||||
color: colors.onSurface.withOpacity(0.12), // track color
|
||||
style: PaintingStyle.fill,
|
||||
)..rrect(
|
||||
color: Colors.transparent, // track outline color
|
||||
style: PaintingStyle.stroke,
|
||||
)..rrect(color: colors.surface.withOpacity(1.0)),
|
||||
);
|
||||
|
||||
await tester.pumpWidget(Container());
|
||||
await tester.pumpWidget(buildApp(enabled: false, value: false));
|
||||
await tester.press(find.byType(Switch));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(Material.of(tester.element(find.byType(Switch))),
|
||||
paints..rrect(
|
||||
color: colors.surfaceVariant.withOpacity(0.12), // track color
|
||||
style: PaintingStyle.fill,
|
||||
)..rrect(
|
||||
color: colors.onSurface.withOpacity(0.12), // track outline color
|
||||
style: PaintingStyle.stroke,
|
||||
)..rrect(color: Color.alphaBlend(colors.onSurface.withOpacity(0.38), colors.surface)),
|
||||
);
|
||||
}, variant: TargetPlatformVariant.mobile());
|
||||
|
||||
testWidgets('Switch thumb color resolves in active/enabled states - M3', (WidgetTester tester) async {
|
||||
final ThemeData themeData = ThemeData(useMaterial3: true, colorSchemeSeed: const Color(0xff6750a4), brightness: Brightness.light);
|
||||
final ColorScheme colors = themeData.colorScheme;
|
||||
|
Loading…
x
Reference in New Issue
Block a user