美文网首页
flutter 中缩放手势延迟的问题(手势冲突)

flutter 中缩放手势延迟的问题(手势冲突)

作者: Nomo_C | 来源:发表于2020-12-10 20:34 被阅读0次

    最近项目中有个需求,widget要能够移动、旋转、点击,代码实现如下。

    
    class GestureDetectorDemo extends StatefulWidget {
      @override
      _GestureDetectorDemoState createState() => _GestureDetectorDemoState();
    }
    
    class _GestureDetectorDemoState extends State<GestureDetectorDemo> {
      bool _show = true;
      @override
      Widget build(BuildContext context) {
        // final control = TransformationController();
        // control.
        return _buildPanel();
      }
    
      //静止状态下的offset
      Offset _idleOffset = Offset(0, 0);
      //本次移动的offset
      Offset _moveOffset = Offset(0, 0);
      //最后一次down事件的offset
      Offset _lastStartOffset = Offset(0, 0);
      double _previousScale = 1;
      double _scale = 1;
    
      double _itemWidth = 150;
      double _itemHeight = 150;
      Widget _buildPanel() {
        return Transform.scale(
          scale: _scale,
          alignment: Alignment(0, 0),
          child: Transform.translate(
            offset: _moveOffset,
            child: GestureDetector(
                onScaleStart: _onScaleStart,
                onScaleUpdate: _onScaleUpdate,
                onScaleEnd: _onScaleEnd,
                onTap: _onTap,
                child: Container(
                  color: Colors.red,
                  width: _itemWidth,
                  height: _itemHeight,
    
                )),
          ),
        );
      }
    
      void _onTap(){
        print('_onTap');
      }
      void _onScaleStart(ScaleStartDetails details) {
        setState(() {
          _lastStartOffset = details.focalPoint;
          print('onScaleStart $_lastStartOffset');
          Offset local = details.localFocalPoint;
        });
      }
    
      void _onScaleUpdate(ScaleUpdateDetails details) {
        setState(() {
          // 缩放
          _scale = _previousScale * details.scale;
          // 移动
          _moveOffset =
              (details.focalPoint - _lastStartOffset + _idleOffset) / _scale;
    
          // 控制移动边界
          double left =
              (_itemWidth * _scale - _itemWidth) / 2.0 / _scale - _itemWidth / 2;
          double top = ((_itemHeight * _scale - _itemHeight) / 2.0) / _scale -
              _itemHeight / 2;
          _moveOffset = Offset(max(left, _moveOffset.dx), max(top, _moveOffset.dy));
    
          double right = (SizeFit.screenWidth -
                      _itemWidth -
                      (_itemWidth * _scale - _itemWidth) / 2.0) /
                  _scale +
              _itemWidth / 2;
          double bottom = (SizeFit.screenHeight -
                      _itemHeight -
                      (_itemHeight * _scale - _itemHeight) / 2.0 -
                      LayoutUtil.getAppBarHeight(context)) /
                  _scale +
              _itemHeight / 4;
          _moveOffset =
              Offset(min(right, _moveOffset.dx), min(bottom, _moveOffset.dy));
        });
      }
    
      void _onScaleEnd(ScaleEndDetails details) {
        print('onScaleEnd');
    
        setState(() {
          _idleOffset = _moveOffset * _scale;
          _previousScale = _scale;
        });
      }
    }
    

    基本功能都使用没什么问题,但是测试中发现在进行缩放的时候总是延迟,手势执行一定时间后widget才开始缩放。
    造成这种情况的原因应该是手势冲突,解决的思路是用Listener处理tap事件,GestureDetector只处理缩放和移动事件。代码如下

    
    class GestureDetectorDemo extends StatefulWidget {
     @override
     _GestureDetectorDemoState createState() => _GestureDetectorDemoState();
    }
    
    class _GestureDetectorDemoState extends State<GestureDetectorDemo> {
     bool _show = true;
     @override
     Widget build(BuildContext context) {
       // final control = TransformationController();
       // control.
       return _buildPanel();
     }
    
     //静止状态下的offset
     Offset _idleOffset = Offset(0, 0);
     //本次移动的offset
     Offset _moveOffset = Offset(0, 0);
     //最后一次down事件的offset
     Offset _lastStartOffset = Offset(0, 0);
     double _previousScale = 1;
     double _scale = 1;
    
     double _itemWidth = 150;
     double _itemHeight = 150;
    
     Duration _tapDownTimeStamp;
    
     Widget _buildPanel() {
       return Transform.scale(
         scale: _scale,
         alignment: Alignment(0, 0),
         child: Transform.translate(
           offset: _moveOffset,
           child: Listener(
             onPointerDown: (PointerDownEvent event) {
               // 记录点击时间
               _tapDownTimeStamp = event.timeStamp;
             },
             onPointerUp: (PointerUpEvent event) {
               // 手指抬起时,计算时间差,100ms以内算点击事件
               int interval = event.timeStamp.inMilliseconds -
                   _tapDownTimeStamp.inMilliseconds;
    
               if (interval <= 100) {
                 // 处理tap事件
                 _onTap();
               }
             },
             child: GestureDetector(
                 onScaleStart: _onScaleStart,
                 onScaleUpdate: _onScaleUpdate,
                 onScaleEnd: _onScaleEnd,
                 child: Container(
                   color: Colors.red,
                   width: _itemWidth,
                   height: _itemHeight,
                 )),
           ),
         ),
       );
     }
    
     void _onTap() {
       print('_onTap');
     }
    
     void _onScaleStart(ScaleStartDetails details) {
       setState(() {
         _lastStartOffset = details.focalPoint;
         print('onScaleStart $_lastStartOffset');
         Offset local = details.localFocalPoint;
       });
     }
    
     void _onScaleUpdate(ScaleUpdateDetails details) {
       setState(() {
         // 缩放
         _scale = _previousScale * details.scale;
         // 移动
         _moveOffset =
             (details.focalPoint - _lastStartOffset + _idleOffset) / _scale;
    
         // 控制移动边界
         double left =
             (_itemWidth * _scale - _itemWidth) / 2.0 / _scale - _itemWidth / 2;
         double top = ((_itemHeight * _scale - _itemHeight) / 2.0) / _scale -
             _itemHeight / 2;
         _moveOffset = Offset(max(left, _moveOffset.dx), max(top, _moveOffset.dy));
    
         double right = (SizeFit.screenWidth -
                     _itemWidth -
                     (_itemWidth * _scale - _itemWidth) / 2.0) /
                 _scale +
             _itemWidth / 2;
         double bottom = (SizeFit.screenHeight -
                     _itemHeight -
                     (_itemHeight * _scale - _itemHeight) / 2.0 -
                     LayoutUtil.getAppBarHeight(context)) /
                 _scale +
             _itemHeight / 4;
         _moveOffset =
             Offset(min(right, _moveOffset.dx), min(bottom, _moveOffset.dy));
       });
     }
    
     void _onScaleEnd(ScaleEndDetails details) {
       print('onScaleEnd');
    
       setState(() {
         _idleOffset = _moveOffset * _scale;
         _previousScale = _scale;
       });
     }
    }
    

    相关文章

      网友评论

          本文标题:flutter 中缩放手势延迟的问题(手势冲突)

          本文链接:https://www.haomeiwen.com/subject/grwrgktx.html