Skip to content

Commit b6cf4dd

Browse files
authored
Merge pull request #42 from splashbyte/version0.8.0
version 0.8.0-beta.6
2 parents 7b05d1a + bca49e9 commit b6cf4dd

15 files changed

Lines changed: 236 additions & 89 deletions

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.8.0-beta.6 (2023-08-22)
2+
3+
- adds parameter to `onTap` ([#41](https://github.com/splashbyte/animated_toggle_switch/issues/41))
4+
15
## 0.8.0-beta.5 (2023-08-18)
26

37
- fixes `AnimationType.onHover`

example/lib/crazy_switch.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class _CrazySwitchState extends State<CrazySwitch> {
2828
animationDuration: const Duration(milliseconds: 350),
2929
animationCurve: Curves.bounceOut,
3030
iconBuilder: (context, local, global) => const SizedBox(),
31-
onTap: () => setState(() => current = !current),
31+
onTap: (_) => setState(() => current = !current),
3232
iconsTappable: false,
3333
onChanged: (b) => setState(() => current = b),
3434
height: height,

example/lib/main.dart

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,9 @@ class _MyHomePageState extends State<MyHomePage> {
154154
colors: [green, Colors.red[800]!],
155155
stops: [
156156
global.position -
157-
(1 - 2 * max(0, global.position - 0.5)) * 0.2,
157+
(1 - 2 * max(0, global.position - 0.5)) * 0.7,
158158
global.position +
159-
max(0, 2 * (global.position - 0.5)) * 0.2,
159+
max(0, 2 * (global.position - 0.5)) * 0.7,
160160
],
161161
));
162162
},
@@ -269,7 +269,7 @@ class _MyHomePageState extends State<MyHomePage> {
269269
Padding(
270270
padding: const EdgeInsets.all(8.0),
271271
child: Text(
272-
'Switch inspired by package lite_rolling_switch',
272+
'Switch similar to package lite_rolling_switch',
273273
textAlign: TextAlign.center,
274274
),
275275
),
@@ -300,10 +300,7 @@ class _MyHomePageState extends State<MyHomePage> {
300300
CupertinoActivityIndicator(
301301
color: Color.lerp(
302302
Colors.red[800], green, global.position)),
303-
onChanged: (b) {
304-
setState(() => positive = b);
305-
return Future<dynamic>.delayed(Duration(seconds: 2));
306-
},
303+
onChanged: (b) => setState(() => positive = b),
307304
iconBuilder: (value) => value
308305
? Icon(Icons.power_outlined, color: green, size: 32.0)
309306
: Icon(Icons.power_settings_new_rounded,
@@ -375,6 +372,7 @@ class _MyHomePageState extends State<MyHomePage> {
375372
active: false,
376373
current: value,
377374
values: const [0, 1, 2, 3],
375+
indicatorIconScale: sqrt2,
378376
onChanged: (i) {
379377
setState(() {
380378
value = i;
@@ -423,6 +421,7 @@ class _MyHomePageState extends State<MyHomePage> {
423421
)
424422
],
425423
),
424+
indicatorIconScale: sqrt2,
426425
iconBuilder: coloredRollingIconBuilder,
427426
borderWidth: 3.0,
428427
styleAnimationType: AnimationType.onHover,
@@ -457,7 +456,11 @@ class _MyHomePageState extends State<MyHomePage> {
457456
current: nullableValue,
458457
allowUnlistedValues: true,
459458
values: const [0, 1, 2, 3],
460-
onTap: () => setState(() => nullableValue = null),
459+
onTap: (info) {
460+
if (nullableValue == info.tapped?.value) {
461+
setState(() => nullableValue = null);
462+
}
463+
},
461464
onChanged: (i) => setState(() => nullableValue = i),
462465
iconBuilder: rollingIconBuilder,
463466
borderWidth: 4.5,
@@ -490,7 +493,7 @@ class _MyHomePageState extends State<MyHomePage> {
490493
return const SizedBox();
491494
},
492495
cursors: ToggleCursors(defaultCursor: SystemMouseCursors.click),
493-
onTap: () => setState(() => positive = !positive),
496+
onTap: (_) => setState(() => positive = !positive),
494497
iconsTappable: false,
495498
wrapperBuilder: (context, global, child) {
496499
return Stack(
@@ -703,6 +706,7 @@ class _MyHomePageState extends State<MyHomePage> {
703706
current: value,
704707
values: const [0, 1, 2, 3],
705708
iconOpacity: 1.0,
709+
selectedIconScale: 1.0,
706710
indicatorSize: const Size.fromWidth(25),
707711
foregroundIndicatorIconBuilder: (context, global) {
708712
double pos = global.position;

lib/animated_toggle_switch.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ import 'package:flutter/foundation.dart';
88
import 'package:flutter/gestures.dart';
99
import 'package:flutter/material.dart';
1010

11-
part 'src/animation_type_builder.dart';
11+
part 'src/animations.dart';
1212
part 'src/properties.dart';
1313
part 'src/style.dart';
1414
part 'src/tweens.dart';
1515
part 'src/cursors.dart';
16+
part 'src/widgets/animation_type_builder.dart';
1617
part 'src/foreground_indicator_transition.dart';
1718
part 'src/widgets/animated_toggle_switch.dart';
1819
part 'src/widgets/custom_animated_toggle_switch.dart';

lib/src/animations.dart

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
part of 'package:animated_toggle_switch/animated_toggle_switch.dart';
2+
3+
// this Animation is not covered because it does not contain logic but
4+
// forwards all methods to its parent Animation.
5+
// coverage:ignore-start
6+
/// This class is a proxy for another animation.
7+
///
8+
/// It is used for passing animations in builders without exposing the real
9+
/// animation to the user.
10+
class _PrivateAnimation<T> extends Animation<T> {
11+
final Animation<T> _parent;
12+
13+
_PrivateAnimation(this._parent);
14+
15+
@override
16+
void addListener(VoidCallback listener) => _parent.addListener(listener);
17+
18+
@override
19+
void addStatusListener(AnimationStatusListener listener) =>
20+
_parent.addStatusListener(listener);
21+
22+
@override
23+
void removeListener(VoidCallback listener) =>
24+
_parent.removeListener(listener);
25+
26+
@override
27+
void removeStatusListener(AnimationStatusListener listener) =>
28+
_parent.removeStatusListener(listener);
29+
30+
@override
31+
AnimationStatus get status => _parent.status;
32+
33+
@override
34+
T get value => _parent.value;
35+
}
36+
// coverage:ignore-end

lib/src/properties.dart

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11
// coverage:ignore-file
22
part of 'package:animated_toggle_switch/animated_toggle_switch.dart';
33

4+
class ValueHolder<T> {
5+
final T value;
6+
7+
/// The index of [value] in [values].
8+
///
9+
/// If [values] does not contain [value], this value is set to [-1].
10+
final int index;
11+
12+
ValueHolder({required this.value, required this.index});
13+
}
14+
415
class GlobalToggleProperties<T> {
516
/// The position of the indicator relative to the indices of the values.
617
final double position;
@@ -13,7 +24,7 @@ class GlobalToggleProperties<T> {
1324

1425
/// The index of [current] in [values].
1526
///
16-
/// If [values] does not contain [current], this value is set to [-1].
27+
/// If [values] does not contain [current], [currentIndex] is set to [-1].
1728
final int currentIndex;
1829

1930
/// This value indicates if [values] does contain [current].
@@ -44,6 +55,17 @@ class GlobalToggleProperties<T> {
4455

4556
final bool active;
4657

58+
/// This animation indicates whether the indicator is currently visible.
59+
///
60+
/// [0.0] means it is not visible.
61+
///
62+
/// [1.0] means it is fully visible.
63+
///
64+
/// Depending on the curve of the animation, the value can also be below 0.0 or above 1.0.
65+
///
66+
/// This will be publicly accessible in future releases.
67+
final Animation<double> _indicatorAppearingAnimation;
68+
4769
const GlobalToggleProperties({
4870
required this.position,
4971
required this.current,
@@ -55,7 +77,8 @@ class GlobalToggleProperties<T> {
5577
required this.mode,
5678
required this.loadingAnimationValue,
5779
required this.active,
58-
});
80+
required Animation<double> indicatorAppearingAnimation,
81+
}) : _indicatorAppearingAnimation = indicatorAppearingAnimation;
5982
}
6083

6184
class DetailedGlobalToggleProperties<T> extends GlobalToggleProperties<T> {
@@ -88,6 +111,7 @@ class DetailedGlobalToggleProperties<T> extends GlobalToggleProperties<T> {
88111
required super.mode,
89112
required super.loadingAnimationValue,
90113
required super.active,
114+
required super.indicatorAppearingAnimation,
91115
});
92116
}
93117

@@ -97,7 +121,7 @@ class LocalToggleProperties<T> {
97121

98122
/// The index of [value].
99123
///
100-
/// If [values] does not contain [value], this value is set to [-1].
124+
/// If [values] does not contain [value], this [index] is set to [-1].
101125
final int index;
102126

103127
/// This value indicates if [values] does contain [value].
@@ -181,3 +205,46 @@ class SeparatorProperties<T> {
181205
required this.index,
182206
});
183207
}
208+
209+
class TapProperties<T> {
210+
/// Information about the point on which the user has tapped.
211+
///
212+
/// This value can be [null] if the user taps on the border of an
213+
/// [AnimatedToggleSwitch] or on the wrapper of a
214+
/// [CustomAnimatedToggleSwitch].
215+
final TapInfo<T>? tapped;
216+
217+
/// The values which are given to the switch.
218+
///
219+
/// Helpful if the list is generated e.g.
220+
/// when the switch constructor is called.
221+
final List<T> values;
222+
223+
const TapProperties({
224+
required this.tapped,
225+
required this.values,
226+
});
227+
}
228+
229+
class TapInfo<T> {
230+
/// The value that the user has tapped.
231+
final T value;
232+
233+
/// The index of [value] in [values].
234+
///
235+
/// [index == position.round()] should always be [true].
236+
final int index;
237+
238+
/// The tapped position relative to the indices of the values.
239+
///
240+
/// [position] can be in the interval from [-0.5] to [values.length - 0.5].
241+
///
242+
/// [position.round() == index] should always be [true].
243+
final double position;
244+
245+
TapInfo({
246+
required this.value,
247+
required this.index,
248+
required this.position,
249+
});
250+
}

lib/src/widgets/animated_toggle_switch.dart

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ abstract class _AnimatedToggleSwitchParent<T> extends StatelessWidget {
7272
/// If you want to implement a completely custom switch,
7373
/// you should use [CustomAnimatedToggleSwitch], which is used by
7474
/// [AnimatedToggleSwitch] in the background.
75-
class AnimatedToggleSwitch<T> extends _AnimatedToggleSwitchParent<T> {
75+
class AnimatedToggleSwitch<T extends Object?>
76+
extends _AnimatedToggleSwitchParent<T> {
7677
/// The currently selected value. It has to be set at [onChanged] or whenever for animating to this value.
7778
///
7879
/// [current] has to be in [values] for working correctly if [allowUnlistedValues] is false.
@@ -168,7 +169,7 @@ class AnimatedToggleSwitch<T> extends _AnimatedToggleSwitchParent<T> {
168169
final AnimationType indicatorAnimationType;
169170

170171
/// Callback for tapping anywhere on the widget.
171-
final TapCallback? onTap;
172+
final TapCallback<T>? onTap;
172173

173174
final IconArrangement _iconArrangement;
174175

@@ -864,7 +865,7 @@ class AnimatedToggleSwitch<T> extends _AnimatedToggleSwitchParent<T> {
864865
this.styleAnimationType = AnimationType.onHover,
865866
this.indicatorAnimationType = AnimationType.onHover,
866867
this.fittingMode = FittingMode.preventHorizontalOverlapping,
867-
Function()? onTap,
868+
TapCallback<T>? onTap,
868869
this.minTouchTargetSize = 48.0,
869870
this.textDirection,
870871
this.cursors = const ToggleCursors(defaultCursor: SystemMouseCursors.click),
@@ -923,9 +924,9 @@ class AnimatedToggleSwitch<T> extends _AnimatedToggleSwitchParent<T> {
923924
iconList: null,
924925
);
925926

926-
static Function() _dualOnTap<T>(
927+
static TapCallback<T> _dualOnTap<T>(
927928
ChangeCallback<T>? onChanged, List<T> values, T? current) {
928-
return () =>
929+
return (info) =>
929930
onChanged?.call(values.firstWhere((element) => element != current));
930931
}
931932

lib/src/animation_type_builder.dart renamed to lib/src/widgets/animation_type_builder.dart

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,21 +53,20 @@ class _AnimationTypeHoverBuilderState<T, V>
5353
final values = widget.properties.values;
5454
final index1 = pos.floor();
5555
final index2 = pos.ceil();
56-
final isListed = widget.properties.isCurrentListed;
5756
V listedValueFunction() => widget.lerp(
5857
widget.valueProvider(
5958
StyledToggleProperties(value: values[index1], index: index1)),
6059
widget.valueProvider(
6160
StyledToggleProperties(value: values[index2], index: index2)),
6261
pos - pos.floor(),
6362
);
64-
final unlistedDoubleValue = isListed ? 0.0 : 1.0;
65-
return TweenAnimationBuilder<double>(
66-
duration: widget.indicatorAppearingDuration,
67-
curve: widget.indicatorAppearingCurve,
68-
tween: Tween(begin: unlistedDoubleValue, end: unlistedDoubleValue),
69-
builder: (context, unlistedDoubleValue, _) {
70-
if (unlistedDoubleValue == 0.0) {
63+
final indicatorAppearingAnimation =
64+
widget.properties._indicatorAppearingAnimation;
65+
return AnimatedBuilder(
66+
animation: indicatorAppearingAnimation,
67+
builder: (context, _) {
68+
final appearingValue = indicatorAppearingAnimation.value;
69+
if (appearingValue >= 1.0) {
7170
return _EmptyWidget(
7271
key: _builderKey, child: widget.builder(listedValueFunction()));
7372
}
@@ -81,10 +80,10 @@ class _AnimationTypeHoverBuilderState<T, V>
8180
builder: (context, unlistedValue, _) {
8281
return _EmptyWidget(
8382
key: _builderKey,
84-
child: widget.builder(unlistedDoubleValue == 1.0
83+
child: widget.builder(appearingValue <= 0.0
8584
? unlistedValue
86-
: widget.lerp(listedValueFunction(), unlistedValue,
87-
unlistedDoubleValue)),
85+
: widget.lerp(
86+
unlistedValue, listedValueFunction(), appearingValue)),
8887
);
8988
});
9089
},

0 commit comments

Comments
 (0)