75 lines
1.9 KiB
Dart
75 lines
1.9 KiB
Dart
|
import 'dart:math';
|
||
|
import 'package:flutter/material.dart';
|
||
|
|
||
|
class RepeatOnHoldButton extends StatefulWidget {
|
||
|
/// Function to be called on tap and on long press.
|
||
|
/// Return [false] to signify that the loop should be broken after execution.
|
||
|
final bool? Function() onTap;
|
||
|
|
||
|
/// Specifies whether repetition speeds up when the user keeps holding the button.
|
||
|
final bool increaseSpeed;
|
||
|
|
||
|
/// Specifies how many ms should pass before action is repeated.
|
||
|
final int initialRepetitionIntervalMs;
|
||
|
|
||
|
/// Specifies by how much the interval between actions should be divided after [speedUpAfterTimes] times.
|
||
|
final int speedUpFactor;
|
||
|
|
||
|
/// Specifies how many times [onTap] will be called before increasing the speed.
|
||
|
final int speedUpAfterTimes;
|
||
|
|
||
|
final Widget child;
|
||
|
|
||
|
const RepeatOnHoldButton({
|
||
|
Key? key,
|
||
|
required this.onTap,
|
||
|
this.increaseSpeed = true,
|
||
|
this.initialRepetitionIntervalMs = 250,
|
||
|
this.speedUpFactor = 2,
|
||
|
this.speedUpAfterTimes = 5,
|
||
|
required this.child,
|
||
|
}) : super(key: key);
|
||
|
|
||
|
@override
|
||
|
_RepeatOnHoldButtonState createState() => _RepeatOnHoldButtonState();
|
||
|
}
|
||
|
|
||
|
class _RepeatOnHoldButtonState extends State<RepeatOnHoldButton> {
|
||
|
bool _isHeld = false;
|
||
|
|
||
|
void onLongPress() async {
|
||
|
setState(() {
|
||
|
_isHeld = true;
|
||
|
});
|
||
|
int holdCycle = 0;
|
||
|
int speed = widget.initialRepetitionIntervalMs;
|
||
|
|
||
|
while (true) {
|
||
|
final result = widget.onTap() ?? true;
|
||
|
if (!_isHeld || !result) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
holdCycle++;
|
||
|
if (speed > 1 && holdCycle % widget.speedUpAfterTimes == 0) {
|
||
|
speed = max(1, (speed ~/ widget.speedUpFactor));
|
||
|
}
|
||
|
|
||
|
await Future.delayed(
|
||
|
Duration(
|
||
|
milliseconds: speed,
|
||
|
),
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
Widget build(BuildContext context) {
|
||
|
return GestureDetector(
|
||
|
onLongPress: onLongPress,
|
||
|
onLongPressEnd: (_) => _isHeld = false,
|
||
|
child: widget.child,
|
||
|
);
|
||
|
}
|
||
|
}
|