在堆栈中的两个小部件之间传递所有手势 [英] Pass trough all gestures between two widgets in Stack

查看:102
本文介绍了在堆栈中的两个小部件之间传递所有手势的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个在地图上显示标记的应用程序,如下所示:

I'm working on an app where I display markers over a map like so:

它的工作方式是将标记渲染到上方"​​.Map小部件为 Stack .我的问题是,目前,标记吸收"了用于控制下方地图的手势(如果手势从标记上开始).

The way it works is markers are rendered "over" the Map widget as Stack. My problem is that currently, the markers 'absorbs' the gestures used to control the map underneath (if the gesture starts on the marker).

因此,我想知道,是否有办法在堆栈中两个小部件之间传递所有手势事件?理想情况下,标记会忽略(并通过)除 onTap 之外的所有事件(因为我仍然希望能够单击标记).

I was therefore wondering, is there a way to pass through all gestures events between two widgets in a stack? Ideally, the marker would ignore (and pass through) all events except onTap (as I still want to be able to click on the markers).

这是我的特定树种:

干杯!

推荐答案

(在视觉上)位于同一堆栈中另一个控件顶部的控件被命中时,该堆栈将停止任何进一步的命中测试.因此,在您的情况下,必须使包含 GoogleMap 小部件的堆栈的第二个子项报告未命中,以便堆栈为 GoogleMap 提供机会对指针事件做出反应. IgnorePointer 可以做到这一点,但是该小部件也不会命中测试其子级,因此其子级手势检测器永远不会涉及任何手势.在简单的情况下,可以通过将 IgnorePointer GestureDetector 的顺序互换,同时将后者的 behavior 属性设置为 HitTestBehaviour来解决此问题..translucent .例如:

When a widget that is (visually) on top of another widget in the same stack is hit, the stack will stop any further hit testing. So, in your case, the second child of the stack containing the GoogleMap widget must be made to report that it is not hit, so the stack will give GoogleMap a chance to react to pointer events. IgnorePointer can do that, however that widget will also not hit test its child, so its child gesture detectors will never be involved in any gesture. In simple cases, that can be worked-around by swapping the order of IgnorePointer and GestureDetector while setting the latter's behavior property to HitTestBehaviour.translucent. For example:

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) => MaterialApp(
        home: Stack(
          fit: StackFit.expand,
          children: [
            GestureDetector(
              onDoubleTap: () => print("double red"),
              child: Container(color: Colors.red),
            ),
            Positioned(
              top: 100,
              left: 100,
              right: 100,
              bottom: 100,
              child: GestureDetector(
                behavior: HitTestBehavior.translucent,
                onTap: () => print("green"),
                child: IgnorePointer(
                  child: Container(color: Colors.green),
                ),
              ),
            ),
          ],
        ),
      );
}

您的案子比较复杂.一种更通用的方法是创建一个像 IgnorePointer 之类的新小部件(我们称其为 TransparentPointer ),该小部件可以对它起作用,就像它从未被击中一样,而仍然在被击中对它的孩子进行测试.在这里,我复制了 IgnorePointer 并以这种方式更改了行为(关于 RenderIgnorePointer 的唯一更改是在 RenderTransparentPointer.hitTest 中):

Your case is more complicated though. A more generic approach would be to create a new widget like IgnorePointer (let's call it TransparentPointer) that can act to it parent as if it is never hit, while still doing hit testing on its child. Here I've copied IgnorePointer and changed the behavior in that way (the only change with respect to RenderIgnorePointer is in RenderTransparentPointer.hitTest):

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) => MaterialApp(
        home: Stack(
          fit: StackFit.expand,
          children: [
            GestureDetector(
              onDoubleTap: () => print("double red"),
              child: Container(color: Colors.red),
            ),
            TransparentPointer(
              transparent: true,
              child: Stack(
                children: [
                  Positioned(
                    top: 100,
                    left: 100,
                    right: 100,
                    bottom: 100,
                    child: GestureDetector(
                      onTap: () => print("green"),
                      child: Container(color: Colors.green),
                    ),
                  )
                ],
              ),
            ),
          ],
        ),
      );
}

class TransparentPointer extends SingleChildRenderObjectWidget {
  const TransparentPointer({
    Key key,
    this.transparent = true,
    Widget child,
  })  : assert(transparent != null),
        super(key: key, child: child);

  final bool transparent;

  @override
  RenderTransparentPointer createRenderObject(BuildContext context) {
    return RenderTransparentPointer(
      transparent: transparent,
    );
  }

  @override
  void updateRenderObject(BuildContext context, RenderTransparentPointer renderObject) {
    renderObject
      ..transparent = transparent;
  }

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.add(DiagnosticsProperty<bool>('transparent', transparent));
  }
}

class RenderTransparentPointer extends RenderProxyBox {
  RenderTransparentPointer({
    RenderBox child,
    bool transparent = true,
  })  : _transparent = transparent,
        super(child) {
    assert(_transparent != null);
  }

  bool get transparent => _transparent;
  bool _transparent;

  set transparent(bool value) {
    assert(value != null);
    if (value == _transparent) return;
    _transparent = value;
  }

  @override
  bool hitTest(BoxHitTestResult result, {@required Offset position}) {
    // forward hits to our child:
    final hit = super.hitTest(result, position: position);
    // but report to our parent that we are not hit when `transparent` is true:
    return !transparent && hit;
  }

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.add(DiagnosticsProperty<bool>('transparent', transparent));
  }
}

我已将此代码作为一个小程序包发布: https://pub.dev/packages/transparent_pointer

I have published this code as a small package: https://pub.dev/packages/transparent_pointer

这篇关于在堆栈中的两个小部件之间传递所有手势的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆