无法可靠地在手势检测器上长按触发动画



我正在尝试创建一个带有进度指示器(CircularProgressIndicator)的按钮

想要流:

  1. 用户点击按钮,应该触发一个功能
  2. 用户按下按钮(并按住),它应该触发动画并触发一个函数
  3. 当用户释放hold时,它应该重置动画并触发一个函数

此时,我的代码在第二次按下(并按住)元素时工作。第一次,动画控制器的addListener打印2-3次,然后停止,而第二次,它保持为真,并在用户持有元素时继续打印。Ontap功能无论如何都可以工作。

在android和ios设备上本地运行时发生

剥离代码块:

import 'package:flutter/material.dart';
import 'package:homi_frontend/constants/woopen_colors.dart';
class ProgressButton extends StatefulWidget {
ProgressButton({
@required this.onTap,
@required this.onLongPress,
@required this.onLongPressUp,
this.duration = const Duration(seconds: 60),
});
final Function onTap;
final Function onLongPress;
final Function onLongPressUp;
final Duration duration;
@override
ProgressButtonState createState() => ProgressButtonState();
}
class ProgressButtonState extends State<ProgressButton>
with SingleTickerProviderStateMixin {
AnimationController _animationController;
bool _beingPressed = false;
@override
void initState() {
_animationController = AnimationController(
vsync: this,
duration: widget.duration,
);
_animationController.addListener(_animationListener);
_animationController.addStatusListener(_animationStatusListener);
super.initState();
}
void _animationListener() {
print('Animation Controller Listener');
setState(() {});
}
void _animationStatusListener(AnimationStatus status) {
print('_animationStatusListener');
if (status == AnimationStatus.completed) {
print(
'Completed duration of ${widget.duration}, fire _handleOnLongPressUp');
_handleOnLongPressUp();
}
if (status == AnimationStatus.forward) {
this.setState(() {
_beingPressed = true;
});
}
}
void _handleOnLongPress() {
print('_handleOnLongPress');
try {
_animationController.forward();
} catch (e) {
print('_handleOnLongPress error: ${e.toString()}');
} finally {
if (_animationController.status == AnimationStatus.forward) {
print('Controller has been started, fire widget.onLongPress');
widget.onLongPress();
}
}
}
void _handleOnLongPressUp() {
print('_handleOnLongPressUp');
try {
this.setState(() {
_beingPressed = false;
});
_animationController.reset();
} catch (e) {
print('_handleOnLongPressUp error: ${e.toString()}');
} finally {
if (_animationController.status == AnimationStatus.dismissed) {
print('Controller has been dismissed, fire widget.onLongPressUp');
widget.onLongPressUp();
}
}
}
@override
dispose() {
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return GestureDetector(
key: Key('progressButtonGestureDetector'),
behavior: HitTestBehavior.opaque,
onLongPress: _handleOnLongPress,
onLongPressUp: _handleOnLongPressUp,
onTap: widget.onTap,
child: Container(
width: 80,
height: 80,
child: Text(_animationController.value.toStringAsFixed(2)),
),
);
}
}

输出:

flutter: _handleOnLongPress
flutter: _animationStatusListener
flutter: Controller has been started, fire widget.onLongPress
(2) flutter: Animation Controller Listener
# here it just seems to loose its connection, but if I press (and hold) again, I get:
flutter: _handleOnLongPress
flutter: _animationStatusListener
flutter: Controller has been started, fire widget.onLongPress
(326) flutter: Animation Controller Listener
flutter: _handleOnLongPressUp
flutter: Animation Controller Listener
flutter: _animationStatusListener
flutter: Controller has been dismissed, fire widget.onLongPressUp

我也简要地研究了RawGestureDetector,但只有我的TapGestureRecognizer手势似乎开火,LongPressGestureRecognizer的没有…即使TapGestureRecognizers被移除

_customGestures = Map<Type, GestureRecognizerFactory>();
_customGestures[TapGestureRecognizer] =
GestureRecognizerFactoryWithHandlers<TapGestureRecognizer>(
() => TapGestureRecognizer(debugOwner: this),
(TapGestureRecognizer instance) {
instance
..onTapDown = (TapDownDetails details) {
print('onTapDown');
}
..onTapUp = (TapUpDetails details) {
print('onTapUp');
}
..onTap = () {
print('onTap');
}
..onTapCancel = () {
print('onTapCancel');
};
},
);
_customGestures[LongPressGestureRecognizer] =
GestureRecognizerFactoryWithHandlers<LongPressGestureRecognizer>(
() => LongPressGestureRecognizer(
duration: widget.duration, debugOwner: this),
(LongPressGestureRecognizer instance) {
instance
..onLongPress = () {
print('onLongPress');
}
..onLongPressStart = (LongPressStartDetails details) {
print('onLongPressStart');
_animationController.forward();
}
..onLongPressMoveUpdate = (LongPressMoveUpdateDetails details) {
print('onLongPressMoveUpdate');
}
..onLongPressEnd = (LongPressEndDetails details) {
print('onLongPressEnd');
_animationController.reset();
}
..onLongPressUp = () {
print('onLongPressUp');
};
},
);

请及感谢您的宝贵时间!

您正在使用Text小部件来接收命中与拇指相比,GestureDetector有一个小的点击框。这可能就是为什么你偶尔会误点击点击框的原因。

你可以使用debugPaintPointersEnabled更清楚地看到行为(需要做一个热重启,如果应用程序正在运行):

import 'package:flutter/rendering.dart';
void main() {
// Add the config here
debugPaintPointersEnabled = true;
runApp(App());
}

你可以看到,点击框不会一直闪烁,即使我们认为我们击中了文本。为了提高准确性,让我们在Text

周围换行一个有size的Container。
GestureDetector(
// ... other lines
child: Container(
width: 100,
height: 50,
color: Colors.blue,
alignment: Alignment.center,
child:
Text('Value: ${_animationController.value.toStringAsFixed(2)}')),
);

你可以看到点击框现在每次都闪烁

最新更新