无法在 GestureDetector 上使用 longPress 可靠地触发动画

问题描述

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

所需的流量:

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

此时,我的代码在第二次按下(并按住)元素时起作用。第一次,动画控制器的 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 的手势不会......即使 TapGestureRecognizer 是已删除

_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());
}

您可以看到点击框不会一直闪烁,即使我们认为我们点击了文本。为了提高准确性,让我们在文本周围包裹一个大小为 Container

GestureDetector(

      // ... other lines

      child: Container(
          width: 100,height: 50,color: Colors.blue,alignment: Alignment.center,child:
              Text('Value: ${_animationController.value.toStringAsFixed(2)}')),);

你可以看到命中框现在每次都闪烁

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...