diff --git a/CHANGELOG.md b/CHANGELOG.md index 06e7ccc..5d66369 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,11 @@ -## 0.6.0 (2022-12-05) +## 0.6.0 (2022-12-22) - fixes README +- fixes #28 - BREAKING: Increases minimum SDK to 2.17 - BREAKING: Renames `value` to `current` and `previousValue` to `previous` in `DetailedGlobalToggleProperties` - BREAKING Feature: Adds loading animation to all switches. You can disable it by setting `loading` to false. +- Adds `innerGradient` to `AnimatedToggleSwitch` +- Adds `transitionType` to `AnimatedToggleSwitch.rolling`, `AnimatedToggleSwitch.rollingByHeight` and `AnimatedToggleSwitch.dual` ## 0.5.2 (2022-04-22) - Minor performance improvement diff --git a/example/lib/main.dart b/example/lib/main.dart index 364d0df..4d51c92 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -116,7 +116,8 @@ class _MyHomePageState extends State { value = i; loading = true; }); - return Future.delayed(Duration(seconds: 3)).then((_) => setState(()=>loading = false)); + return Future.delayed(Duration(seconds: 3)) + .then((_) => setState(() => loading = false)); }, iconBuilder: rollingIconBuilder, borderColor: Colors.transparent, @@ -144,7 +145,9 @@ class _MyHomePageState extends State { onChanged: (i) => setState(() => value = i), iconBuilder: rollingIconBuilder, borderWidth: 4.5, - indicatorColor: Colors.purpleAccent, + indicatorColor: Colors.white, + innerGradient: + const LinearGradient(colors: [Colors.red, Colors.blue]), innerColor: Colors.amber, height: 55, dif: 20.0, diff --git a/example/pubspec.lock b/example/pubspec.lock index 9fa306d..3f876be 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -7,7 +7,7 @@ packages: path: ".." relative: true source: path - version: "0.5.2" + version: "0.6.0" async: dependency: transitive description: diff --git a/lib/src/widgets/animated_toggle_switch.dart b/lib/src/widgets/animated_toggle_switch.dart index 058e317..f9fff22 100644 --- a/lib/src/widgets/animated_toggle_switch.dart +++ b/lib/src/widgets/animated_toggle_switch.dart @@ -29,8 +29,35 @@ typedef IconBuilder = Widget Function(BuildContext context, typedef ColorBuilder = Color? Function(T value); -enum AnimationType { onSelected, onHover } +/// Specifies when an icon should be highlighted. +enum AnimationType { + /// Starts an animation if an item is selected. + onSelected, + /// Start an animation if an item is hovered by the indicator. + onHover, +} + +/// Different types of transitions for the foreground indicator. +/// +/// Currently this enum is used only for deactivating the rolling animation in +/// some constructors. +enum ForegroundIndicatorTransitionType { + /// Fades between the different icons. + fading, + + /// Fades between the different icons and shows a rolling animation + /// additionally. + rolling, +} + +/// A class with different constructors of different switches. +/// The constructors have sensible default values for their parameters, +/// but can also be customized. +/// +/// If you want to implement a completely custom switch, +/// you should use [CustomAnimatedToggleSwitch], which is used by +/// [AnimatedToggleSwitch] in the background. class AnimatedToggleSwitch extends StatelessWidget { /// The currently selected value. It has to be set at [onChanged] or whenever for animating to this value. /// @@ -83,6 +110,9 @@ class AnimatedToggleSwitch extends StatelessWidget { /// Color of the background. final Color? innerColor; + /// Gradient of the background. Overwrites [innerColor] if not null. + final Gradient? innerGradient; + /// Opacity for the icons. /// /// Please set [iconOpacity] and [selectedIconOpacity] to 1.0 for deactivating the AnimatedOpacity. @@ -225,6 +255,7 @@ class AnimatedToggleSwitch extends StatelessWidget { this.loading, this.loadingAnimationDuration, this.loadingAnimationCurve, + this.innerGradient, }) : this._iconArrangement = IconArrangement.row, super(key: key); @@ -276,6 +307,7 @@ class AnimatedToggleSwitch extends StatelessWidget { this.loading, this.loadingAnimationDuration, this.loadingAnimationCurve, + this.innerGradient, }) : animatedIconBuilder = _iconSizeBuilder( iconBuilder, customIconBuilder, iconSize, selectedIconSize), this._iconArrangement = IconArrangement.row, @@ -330,6 +362,7 @@ class AnimatedToggleSwitch extends StatelessWidget { this.loading, this.loadingAnimationDuration, this.loadingAnimationCurve, + this.innerGradient, }) : this.indicatorSize = indicatorSize * (height - 2 * borderWidth), this.dif = dif * (height - 2 * borderWidth), animatedIconBuilder = _iconSizeBuilder( @@ -413,6 +446,7 @@ class AnimatedToggleSwitch extends StatelessWidget { this.loading, this.loadingAnimationDuration, this.loadingAnimationCurve, + this.innerGradient, }) : this.dif = dif * (height - 2 * borderWidth), this.indicatorSize = indicatorSize * (height - 2 * borderWidth), this._iconArrangement = IconArrangement.row, @@ -468,6 +502,9 @@ class AnimatedToggleSwitch extends StatelessWidget { this.loading, this.loadingAnimationDuration, this.loadingAnimationCurve, + ForegroundIndicatorTransitionType transitionType = + ForegroundIndicatorTransitionType.rolling, + this.innerGradient, }) : this.iconAnimationCurve = Curves.linear, this.dif = dif * (height - 2 * borderWidth), this.iconAnimationDuration = Duration.zero, @@ -480,7 +517,8 @@ class AnimatedToggleSwitch extends StatelessWidget { iconBuilder, customIconBuilder, Size.square( - selectedIconRadius * 2 * (height - 2 * borderWidth))), + selectedIconRadius * 2 * (height - 2 * borderWidth)), + transitionType), animatedIconBuilder = _standardIconBuilder( iconBuilder, customIconBuilder, @@ -536,13 +574,20 @@ class AnimatedToggleSwitch extends StatelessWidget { this.loading, this.loadingAnimationDuration, this.loadingAnimationCurve, + ForegroundIndicatorTransitionType transitionType = + ForegroundIndicatorTransitionType.rolling, + this.innerGradient, }) : this.iconAnimationCurve = Curves.linear, this.iconAnimationDuration = Duration.zero, this.selectedIconOpacity = iconOpacity, this.iconAnimationType = AnimationType.onSelected, this.foregroundIndicatorIconBuilder = - _rollingForegroundIndicatorIconBuilder(values, iconBuilder, - customIconBuilder, Size.square(selectedIconRadius * 2)), + _rollingForegroundIndicatorIconBuilder( + values, + iconBuilder, + customIconBuilder, + Size.square(selectedIconRadius * 2), + transitionType), this.animatedIconBuilder = _standardIconBuilder( iconBuilder, customIconBuilder, @@ -555,7 +600,8 @@ class AnimatedToggleSwitch extends StatelessWidget { List values, SimpleRollingIconBuilder? iconBuilder, RollingIconBuilder? customIconBuilder, - Size iconSize) { + Size iconSize, + ForegroundIndicatorTransitionType transitionType) { assert(iconBuilder == null || customIconBuilder == null); if (customIconBuilder == null && iconBuilder != null) customIconBuilder = @@ -563,10 +609,13 @@ class AnimatedToggleSwitch extends StatelessWidget { return (context, global) { if (customIconBuilder == null) return SizedBox(); double distance = global.dif + global.indicatorSize.width; - double angleDistance = distance / - iconSize.longestSide * - 2 * - (global.textDirection == TextDirection.rtl ? -1.0 : 1.0); + double angleDistance = + transitionType == ForegroundIndicatorTransitionType.rolling + ? distance / + iconSize.longestSide * + 2 * + (global.textDirection == TextDirection.rtl ? -1.0 : 1.0) + : 0.0; final pos = global.position; int first = pos.floor(); double transitionValue = pos - first; @@ -675,6 +724,9 @@ class AnimatedToggleSwitch extends StatelessWidget { this.loading, this.loadingAnimationDuration, this.loadingAnimationCurve, + ForegroundIndicatorTransitionType transitionType = + ForegroundIndicatorTransitionType.rolling, + this.innerGradient, }) : assert(clipAnimation || opacityAnimation), this.iconOpacity = 1.0, this.selectedIconOpacity = 1.0, @@ -687,7 +739,8 @@ class AnimatedToggleSwitch extends StatelessWidget { [first, second], iconBuilder == null ? null : (v, s, f) => iconBuilder(v), customIconBuilder, - Size.square(iconRadius * 2)), + Size.square(iconRadius * 2), + transitionType), this.animatedIconBuilder = _dualIconBuilder( textBuilder, customTextBuilder, @@ -821,7 +874,11 @@ class AnimatedToggleSwitch extends StatelessWidget { borderRadius: borderRadius, ), decoration: BoxDecoration( - color: innerColor ?? theme.scaffoldBackgroundColor, + gradient: innerGradient, + // Redundant check + color: innerGradient != null + ? null + : (innerColor ?? theme.scaffoldBackgroundColor), borderRadius: borderRadius, boxShadow: boxShadow, ), @@ -934,9 +991,13 @@ class AnimatedToggleSwitch extends StatelessWidget { alignment: Alignment.center, children: [ if (loadingValue < 1.0) - Opacity(opacity: 1.0 - loadingValue, child: child), + Opacity( + key: ValueKey(0), + opacity: 1.0 - loadingValue, + child: child), if (loadingValue > 0.0) Opacity( + key: ValueKey(1), opacity: loadingValue, child: loadingIconBuilder(context, global)), ], @@ -989,9 +1050,12 @@ class _MyLoading extends StatelessWidget { @override Widget build(BuildContext context) { - return Theme.of(context).platform.apple - ? CupertinoActivityIndicator() - : CircularProgressIndicator(); + final color = Theme.of(context).iconTheme.color; + return Padding( + padding: const EdgeInsets.all(8.0), + child: Theme.of(context).platform.apple + ? CupertinoActivityIndicator(color: color) + : CircularProgressIndicator(color: color)); } } diff --git a/lib/src/widgets/custom_animated_toggle_switch.dart b/lib/src/widgets/custom_animated_toggle_switch.dart index 4fd47ce..cd494ea 100644 --- a/lib/src/widgets/custom_animated_toggle_switch.dart +++ b/lib/src/widgets/custom_animated_toggle_switch.dart @@ -32,6 +32,10 @@ enum IconArrangement { overlap } +/// With this widget you can implement your own switches with nice animations. +/// +/// For pre-made switches, please use the constructors of [AnimatedToggleSwitch] +/// instead. class CustomAnimatedToggleSwitch extends StatefulWidget { /// The currently selected value. It has to be set at [onChanged] or whenever for animating to this value. /// @@ -241,7 +245,7 @@ class _CustomAnimatedToggleSwitchState void _loading(bool b) { if (b == _animationInfo.loading) return; - if(_animationInfo.toggleMode == ToggleMode.dragged) { + if (_animationInfo.toggleMode == ToggleMode.dragged) { _animationInfo = _animationInfo.none(); _checkValuePosition(); } @@ -662,35 +666,6 @@ class _WidgetPart extends StatelessWidget { } } -class _WidgetPartClipper extends CustomClipper { - final double width, height; - final double left; - - _WidgetPartClipper( - {this.width = double.infinity, - this.height = double.infinity, - required this.left}); - - @override - Rect getClip(Size size) => Rect.fromLTWH(left, 0, width, height); - - @override - bool shouldReclip(covariant CustomClipper oldClipper) => - oldClipper != this; - - @override - bool operator ==(Object other) => - identical(this, other) || - other is _WidgetPartClipper && - runtimeType == other.runtimeType && - width == other.width && - height == other.height && - left == other.left; - - @override - int get hashCode => width.hashCode ^ height.hashCode ^ left.hashCode; -} - /// A class for holding the current state of [_CustomAnimatedToggleSwitchState]. class _AnimationInfo { final double start;