slot_machine_effect 0.0.4
slot_machine_effect: ^0.0.4 copied to clipboard
A slot machine reel for Flutter. Spins up, drifts to a stop on the value you ask for, and rocks into place with a small bounce.
slot_machine_effect #
A slot machine reel for Flutter. Spins up, runs, drifts to a stop on the value you ask for, and rocks into place with a small bounce.
Usage #
final controller = SlotMachineReelController(initialValue: 0);
SlotMachineReel(
height: 125,
width: 300,
values: const [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
controller: controller,
itemBuilder: (value) => Center(child: Text('$value')),
)
// Elsewhere, such as a button's onPressed:
controller.spin(7);
values is everything on the reel, in order. controller is a
SlotMachineReelController that both holds the value the reel rests on and
drives its spins — calling controller.spin(value) names one of the entries
in values, not an index, so the values need not be 0-9, contiguous, or
sorted.
The reel only spins when controller.spin is called. It never spins on its
own, including on load — it sits on the controller's initialValue until
something spins it.
Starting on a placeholder #
Park the reel on a neutral face until a result arrives, by giving the controller a value that isn't a real result:
final controller = SlotMachineReelController(initialValue: -1); // the blank
SlotMachineReel(
height: 125,
width: 300,
values: const [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1], // -1 is the blank
controller: controller,
itemBuilder: (value) =>
Center(child: Text(value == -1 ? '?' : '$value')),
)
// Once a result is ready:
controller.spin(result);
Several reels #
Stagger delay so they stop one after another, like a real machine:
final controllers = [
for (final digit in digits) SlotMachineReelController(initialValue: digit),
];
Row(
children: [
for (var i = 0; i < digits.length; i++)
SlotMachineReel(
height: 100,
width: 60,
values: const [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
controller: controllers[i],
delay: Duration(milliseconds: 200 * i),
itemBuilder: (value) => Center(child: Text('$value')),
),
],
)
// Spin them all together:
for (var i = 0; i < controllers.length; i++) {
controllers[i].spin(digits[i]);
}
Custom symbols #
The values are just labels for the faces — map them to whatever you draw:
const cherry = 0, lemon = 1, bell = 2, seven = 3;
final controller = SlotMachineReelController(initialValue: cherry);
SlotMachineReel(
height: 100,
width: 100,
values: const [cherry, lemon, bell, seven],
controller: controller,
itemBuilder: (value) => Icon(switch (value) {
cherry => Icons.star,
lemon => Icons.favorite,
bell => Icons.notifications,
_ => Icons.bolt,
}),
)
controller.spin(bell);
Properties #
| Property | Default | Description |
|---|---|---|
height, width |
required | Viewport size. height is also each item's extent. |
values |
required | Everything on the reel, in order. |
controller |
required | A SlotMachineReelController that holds the current value and drives spins. |
itemBuilder |
required | Builds the widget for each entry of values. |
delay |
0ms |
Wait before spinning. Stagger this across reels. |
spinRate |
1.0 |
Speed multiplier. 2.0 is twice as fast. How long a spin takes follows from this and spins. |
spins |
3 |
Extra full loops before landing. |
reverse |
false |
Spin towards decreasing values instead. |
bounceExtent |
0.20 |
Overshoot past the target, as a fraction of height. 0 disables it. |
bounceDuration |
260ms |
How long the reel rocks back into place. |
diameterRatio |
4 |
Wheel curvature. Higher looks flatter. |
physics |
none | Scroll physics, if you want the reel draggable. |
onSpinStart |
— | Called when a spin begins, including the delay. |
onSettled |
— | Called once the reel rests on its value. |
SlotMachineReelController #
| Member | Description |
|---|---|
SlotMachineReelController({required int initialValue}) |
The value the reel rests on before its first spin. |
value |
The value the reel currently holds, or is animating towards. |
spin(int target) |
Spins the reel to target. |
Notes #
- Spins are triggered by calling
controller.spin. Unlike a value-driven reel, spinning to the value already held is not a no-op — every call runs a spin. The reel never spins on its own, including on load. - Spamming is safe. Requests arriving during a spin are ignored, so the
motion always runs to completion. Use
onSpinStart/onSettledto disable a button while it runs. - You set the pace, not the deadline.
spinRatefixes the speed andspinsfixes the distance, so the time a spin takes falls out of those two. Every reel then visibly moves at the same speed whatever its target, and a reel with further to go simply takes longer. If you need to know when a spin ends, useonSettledrather than assuming a duration.
Motion #
The spin is one continuous velocity profile integrated into position, rather than separate animations chained together, so there is no speed discontinuity between phases. Both ramps use smoothstep, which has zero slope at each end, so acceleration is continuous too. The wind-down carries slightly past the target and arrives at zero speed — where a real reel's overshoot peak is — and the bounce takes over from rest.