diff --git a/CHANGELOG.md b/CHANGELOG.md index e6413a1..9c76b87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.8.0-beta.5 (2023-08-18) + +- fixes `AnimationType.onHover` + ## 0.8.0-beta.4 (2023-08-18) - BREAKING: removes `IconTheme` for controlling default size of `Icon`s diff --git a/example/lib/main.dart b/example/lib/main.dart index 689ef99..a7b5a37 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -334,6 +334,7 @@ class _MyHomePageState extends State { ), AnimatedToggleSwitch.rolling( current: value, + indicatorIconScale: sqrt2, values: const [0, 1, 2, 3], onChanged: (i) { setState(() => value = i); @@ -350,10 +351,17 @@ class _MyHomePageState extends State { ), AnimatedToggleSwitch.rolling( allowUnlistedValues: true, + styleAnimationType: AnimationType.onHover, current: nullableValue, values: const [0, 1, 2, 3], onChanged: (i) => setState(() => nullableValue = i), iconBuilder: rollingIconBuilder, + customStyleBuilder: (context, local, global) { + final color = local.isValueListed + ? null + : Theme.of(context).colorScheme.error; + return ToggleStyle(borderColor: color, indicatorColor: color); + }, ), Padding( padding: const EdgeInsets.all(8.0), diff --git a/example/pubspec.lock b/example/pubspec.lock index 5578703..3b770ca 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -7,7 +7,7 @@ packages: path: ".." relative: true source: path - version: "0.8.0-beta.3" + version: "0.8.0-beta.5" async: dependency: transitive description: diff --git a/lib/animated_toggle_switch.dart b/lib/animated_toggle_switch.dart index 45044ad..5eca8b4 100644 --- a/lib/animated_toggle_switch.dart +++ b/lib/animated_toggle_switch.dart @@ -8,8 +8,10 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; +part 'src/animation_type_builder.dart'; part 'src/properties.dart'; part 'src/style.dart'; +part 'src/tweens.dart'; part 'src/cursors.dart'; part 'src/foreground_indicator_transition.dart'; part 'src/widgets/animated_toggle_switch.dart'; diff --git a/lib/src/animation_type_builder.dart b/lib/src/animation_type_builder.dart new file mode 100644 index 0000000..0448da2 --- /dev/null +++ b/lib/src/animation_type_builder.dart @@ -0,0 +1,93 @@ +part of 'package:animated_toggle_switch/animated_toggle_switch.dart'; + +class _AnimationTypeHoverBuilder extends StatefulWidget { + final V Function(StyledToggleProperties local) valueProvider; + final V Function(V value1, V value2, double t) lerp; + final Widget Function(V value) builder; + final GlobalToggleProperties properties; + final Duration animationDuration; + final Curve animationCurve; + final Duration indicatorAppearingDuration; + final Curve indicatorAppearingCurve; + + const _AnimationTypeHoverBuilder({ + required this.valueProvider, + required this.lerp, + required this.builder, + required this.properties, + required this.animationDuration, + required this.animationCurve, + required this.indicatorAppearingDuration, + required this.indicatorAppearingCurve, + }); + + @override + State<_AnimationTypeHoverBuilder> createState() => + _AnimationTypeHoverBuilderState(); +} + +class _AnimationTypeHoverBuilderState + extends State<_AnimationTypeHoverBuilder> { + final _builderKey = GlobalKey(); + T? _lastUnlistedValue; + + @override + void initState() { + super.initState(); + if (!widget.properties.isCurrentListed) { + _lastUnlistedValue = widget.properties.current; + } + } + + @override + void didUpdateWidget(covariant _AnimationTypeHoverBuilder oldWidget) { + super.didUpdateWidget(oldWidget); + if (!widget.properties.isCurrentListed) { + _lastUnlistedValue = widget.properties.current; + } + } + + @override + Widget build(BuildContext context) { + final pos = widget.properties.position; + final values = widget.properties.values; + final index1 = pos.floor(); + final index2 = pos.ceil(); + final isListed = widget.properties.isCurrentListed; + V listedValueFunction() => widget.lerp( + widget.valueProvider( + StyledToggleProperties(value: values[index1], index: index1)), + widget.valueProvider( + StyledToggleProperties(value: values[index2], index: index2)), + pos - pos.floor(), + ); + final unlistedDoubleValue = isListed ? 0.0 : 1.0; + return TweenAnimationBuilder( + duration: widget.indicatorAppearingDuration, + curve: widget.indicatorAppearingCurve, + tween: Tween(begin: unlistedDoubleValue, end: unlistedDoubleValue), + builder: (context, unlistedDoubleValue, _) { + if (unlistedDoubleValue == 0.0) { + return _EmptyWidget( + key: _builderKey, child: widget.builder(listedValueFunction())); + } + final unlistedValue = widget.valueProvider( + StyledToggleProperties(value: _lastUnlistedValue as T, index: -1)); + return TweenAnimationBuilder( + duration: widget.animationDuration, + curve: widget.animationCurve, + tween: _CustomTween(widget.lerp, + begin: unlistedValue, end: unlistedValue), + builder: (context, unlistedValue, _) { + return _EmptyWidget( + key: _builderKey, + child: widget.builder(unlistedDoubleValue == 1.0 + ? unlistedValue + : widget.lerp(listedValueFunction(), unlistedValue, + unlistedDoubleValue)), + ); + }); + }, + ); + } +} diff --git a/lib/src/properties.dart b/lib/src/properties.dart index 5bd68bf..773280f 100644 --- a/lib/src/properties.dart +++ b/lib/src/properties.dart @@ -16,6 +16,9 @@ class GlobalToggleProperties { /// If [values] does not contain [current], this value is set to [-1]. final int currentIndex; + /// This value indicates if [values] does contain [current]. + bool get isCurrentListed => currentIndex >= 0; + /// The previous value of the switch. final T? previous; @@ -94,9 +97,12 @@ class LocalToggleProperties { /// The index of [value]. /// - /// This value is [-1] if [values] does not contain [value]. + /// If [values] does not contain [value], this value is set to [-1]. final int index; + /// This value indicates if [values] does contain [value]. + bool get isValueListed => index >= 0; + const LocalToggleProperties({ required this.value, required this.index, diff --git a/lib/src/tweens.dart b/lib/src/tweens.dart new file mode 100644 index 0000000..8a16d02 --- /dev/null +++ b/lib/src/tweens.dart @@ -0,0 +1,10 @@ +part of 'package:animated_toggle_switch/animated_toggle_switch.dart'; + +class _CustomTween extends Tween { + final V Function(V value1, V value2, double t) lerpFunction; + + _CustomTween(this.lerpFunction, {super.begin, super.end}); + + @override + V lerp(double t) => lerpFunction(begin as V, end as V, t); +} diff --git a/lib/src/widgets/animated_toggle_switch.dart b/lib/src/widgets/animated_toggle_switch.dart index 3b9d66b..10dd4ee 100644 --- a/lib/src/widgets/animated_toggle_switch.dart +++ b/lib/src/widgets/animated_toggle_switch.dart @@ -1064,14 +1064,10 @@ class AnimatedToggleSwitch extends _AnimatedToggleSwitchParent { padding: EdgeInsets.all(borderWidth), active: active, wrapperBuilder: (context, global, child) { - return _ConditionalWrapper( - condition: inactiveOpacity < 1.0, - wrapper: (context, child) => AnimatedOpacity( - opacity: global.active ? 1.0 : inactiveOpacity, - duration: inactiveOpacityDuration, - curve: inactiveOpacityCurve, - child: child, - ), + return AnimatedOpacity( + opacity: global.active ? 1.0 : inactiveOpacity, + duration: inactiveOpacityDuration, + curve: inactiveOpacityCurve, child: _animationTypeBuilder( context, styleAnimationType, @@ -1110,7 +1106,6 @@ class AnimatedToggleSwitch extends _AnimatedToggleSwitchParent { }); } - //TODO: extract this method to separate widget Widget _animationTypeBuilder( BuildContext context, AnimationType animationType, @@ -1119,7 +1114,6 @@ class AnimatedToggleSwitch extends _AnimatedToggleSwitchParent { Widget Function(V value) builder, GlobalToggleProperties properties, ) { - double pos = properties.position; switch (animationType) { case AnimationType.onSelected: V currentValue = valueProvider( @@ -1133,23 +1127,15 @@ class AnimatedToggleSwitch extends _AnimatedToggleSwitchParent { builder: (context, value, _) => builder(value), ); case AnimationType.onHover: - final index1 = pos.floor(); - final index2 = pos.ceil(); - final currentValue = properties.currentIndex < 0 - ? valueProvider( - StyledToggleProperties(value: properties.current, index: -1)) - : lerp( - valueProvider(StyledToggleProperties( - value: values[index1], index: index1)), - valueProvider(StyledToggleProperties( - value: values[index2], index: index2)), - pos - pos.floor(), - ); - return TweenAnimationBuilder( - duration: animationDuration, - curve: animationCurve, - tween: _CustomTween(lerp, begin: currentValue, end: currentValue), - builder: (context, value, _) => builder(value), + return _AnimationTypeHoverBuilder( + valueProvider: valueProvider, + lerp: lerp, + builder: builder, + properties: properties, + animationDuration: animationDuration, + animationCurve: animationCurve, + indicatorAppearingDuration: indicatorAppearingDuration, + indicatorAppearingCurve: indicatorAppearingCurve, ); } } @@ -1318,15 +1304,6 @@ class _MyLoading extends StatelessWidget { } } -class _CustomTween extends Tween { - final V Function(V value1, V value2, double t) lerpFunction; - - _CustomTween(this.lerpFunction, {super.begin, super.end}); - - @override - V lerp(double t) => lerpFunction(begin as V, end as V, t); -} - extension _XTargetPlatform on TargetPlatform { bool get isApple => this == TargetPlatform.iOS || this == TargetPlatform.macOS; diff --git a/lib/src/widgets/conditional_wrapper.dart b/lib/src/widgets/conditional_wrapper.dart index 0c38c2b..88a02f1 100644 --- a/lib/src/widgets/conditional_wrapper.dart +++ b/lib/src/widgets/conditional_wrapper.dart @@ -1,5 +1,7 @@ part of 'package:animated_toggle_switch/animated_toggle_switch.dart'; +// this widget is not covered because it is not used currently +// coverage:ignore-start class _ConditionalWrapper extends StatefulWidget { final Widget Function(BuildContext context, Widget child) wrapper; final bool condition; @@ -25,6 +27,7 @@ class _ConditionalWrapperState extends State<_ConditionalWrapper> { return child; } } +// coverage:ignore-end class _EmptyWidget extends StatelessWidget { final Widget child; diff --git a/pubspec.yaml b/pubspec.yaml index 1e6b5a6..8af5fa4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: animated_toggle_switch description: Fully customizable, draggable and animated switch with multiple choices and smooth loading animation. It has prebuilt constructors for rolling and size animations. -version: 0.8.0-beta.4 +version: 0.8.0-beta.5 repository: https://github.com/SplashByte/animated_toggle_switch issue_tracker: https://github.com/SplashByte/animated_toggle_switch/issues