传递 Stack 中两个小部件之间的所有手势

2024-05-18

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

它的工作方式是标记在地图小部件“上方”呈现为Stack。我的问题是,目前,标记“吸收”用于控制下方地图的手势(如果手势在标记上开始)。

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

这是我的具体树:

Cheers!


当(视觉上)位于同一堆栈中另一个小部件顶部的小部件被命中时,堆栈将停止任何进一步的命中测试。因此,在您的情况下,包含堆栈的第二个子级GoogleMap必须使小部件报告它没有被命中,因此堆栈将给出GoogleMap对指针事件做出反应的机会。IgnorePointer可以做到这一点,但是该小部件也不会对其子级进行命中测试,因此其子级手势检测器将永远不会参与任何手势。在简单的情况下,可以通过交换顺序来解决IgnorePointer and GestureDetector同时设置后者的behavior财产给HitTestBehaviour.translucent。例如:

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 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 https://pub.dev/packages/transparent_pointer

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

传递 Stack 中两个小部件之间的所有手势 的相关文章

随机推荐