在 ThinkDigital 提供的解决方案基础上,我的观察是 InkWell
包含了所有必要的事件,可以在没有额外的 GestureDetector
的情况下实现这一功能(我发现 GestureDetector
在长按时会干扰墨水动画)。这是一个我为一个宠物项目实现的控件,当按住时其事件带有递减延迟 (这是一个带图标的圆角按钮,但使用 InkWell
的任何东西都可以):
class TapOrHoldButton extends StatefulWidget {
final VoidCallback onUpdate;
final int minDelay;
final int initialDelay;
final int delaySteps;
final IconData icon;
const TapOrHoldButton(
{Key? key,
required this.onUpdate,
this.minDelay = 80,
this.initialDelay = 300,
this.delaySteps = 5,
required this.icon})
: assert(minDelay <= initialDelay,
"The minimum delay cannot be larger than the initial delay"),
super(key: key);
@override
_TapOrHoldButtonState createState() => _TapOrHoldButtonState();
}
class _TapOrHoldButtonState extends State<TapOrHoldButton> {
bool _holding = false;
@override
Widget build(BuildContext context) {
var shape = CircleBorder();
return Material(
color: Theme.of(context).dividerColor,
shape: shape,
child: InkWell(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(
widget.icon,
color:
Theme.of(context).textTheme.headline1?.color ?? Colors.white70,
size: 36,
),
),
onTap: () => _stopHolding(),
onTapDown: (_) => _startHolding(),
onTapCancel: () => _stopHolding(),
customBorder: shape,
),
);
}
void _startHolding() async {
if (_holding) return;
_holding = true;
final step =
(widget.initialDelay - widget.minDelay).toDouble() / widget.delaySteps;
var delay = widget.initialDelay.toDouble();
while (_holding) {
widget.onUpdate();
await Future.delayed(Duration(milliseconds: delay.round()));
if (delay > widget.minDelay) delay -= step;
}
}
void _stopHolding() {
_holding = false;
}
}
这是它的实际应用效果:
GestureLongPressCallback onLongPress
属性出了什么问题? - pskink