如何检测 GestureDetector 是不是悬停在 Flutter 中?

Posted

技术标签:

【中文标题】如何检测 GestureDetector 是不是悬停在 Flutter 中?【英文标题】:How do I detect if a GestureDetector is hovered in Flutter?如何检测 GestureDetector 是否悬停在 Flutter 中? 【发布时间】:2021-03-09 13:20:34 【问题描述】:

所以我在 Flutter 中有一个小部件 GestureDetector,我希望它在“悬停”时做一些事情,就像这样(向任何方向拖动):

GestureDetector 可以做到吗?任何帮助表示赞赏。

【问题讨论】:

【参考方案1】:

我不熟悉使用 GestureDetector 执行此操作的方法,因为我相信所有手势都需要在 GestureDetector 小部件内开始。可以将容器包装在 GestureDetector 中并确定指针何时位于容器顶部。

如果您尝试在 Web 或桌面设备上执行此操作,您可以使用 MouseRegion 小部件。如果您转到该链接,您会看到它检测鼠标进入和退出的难易程度。

还有 Draggable 小部件可以与 DraggableTarget 小部件结合使用来做一些很酷的事情。

【讨论】:

谢谢!我会试试看。当用户在屏幕上滑动手指时,它是否适用于移动设备?【参考方案2】:

您可以创建一个非常小的盒子并在拖动时将其移动,然后实现一些碰撞(此包:https://pub.dev/packages/slowly_moving_widgets_field),并检查您的小盒子是否与 GestureDetector 的盒子发生碰撞。

如果发生碰撞 -> 悬停返回 如果不是 -> 没有悬停

【讨论】:

【参考方案3】:

您可以使用 Listener 类包装您的 Gesturedetector 或任何小部件,并监听拖动的位置,并根据这些值执行一些任务。

【讨论】:

如果触摸是从我的小部件外部开始的,则不会在Listener 小部件上触发任何事件。例如,在 Listener 文档中,如果您从蓝色小部件外部开始您的手势,则在悬停蓝色小部件时没有任何反应。【参考方案4】:

鼠标区域

MouseRegion 小部件 MouseRegion 暴露了一些与鼠标相关的事件,你猜对了。这些事件是:

OnEnter, which will trigger when your mouse enters the Widget.
OnExit, which will trigger when your mouse leaves the Widget.
OnHover, which will trigger both when your mouse enters the Widget and on every subsequent move inside the Widget.

所有这些实际上都是 PointerEvents,它返回有关用户指针的各种信息。在这里,我们将查看用户鼠标在包含 Widget 中的当前位置,该 Widget 以 Offset 的名义存储。

 class _MyHoverableWidgetState extends State<MyHoverableWidget>
        // Our state
        bool amIHovering = false;
        Offset exitFrom = Offset(0,0);
    
        return MouseRegion(
            onEnter: (PointerDetails details) => setState(() => amIHovering = true),
            onExit: (PointerDetails details) => setState(()  
                amIHovering = false;
                exitFrom = details.localPosition; // You can use details.position if you are interested in the global position of your pointer.
            ),
            child: Container(
                width: 200,
                height: 200,
                child: Center(
                    child:Text(amIHovering ? "Look mom, I'm hovering" : "I exited from: $exitFrom"),
                ), 
            ),
        );

    

【讨论】:

MouseRegion的事件也是由手势触发的吗? (例如在 iosandroid 中,不在网络或桌面中)【参考方案5】:
    用手势检测器包装父窗口小部件。这是为了满足在目标小部件范围之外触发​​悬停事件的情况。 获取应响应“悬停”事件的小部件的位置/区域。确保在构建小部件树之前执行此操作,即有状态小部件的 initState。此外,这应该是绝对的视口。您不希望屏幕滚动时满足条件(下)的情况 使用回调函数向手势检测器添加监听器,当在目标小部件的范围内检测到“悬停”时进行监听并更新。

因此,简而言之,如果目标边界位于坐标 x1(0)、x2(10)、y1(0)、y2(8) 内

// Sample callbackCode to check if within
// x and y are the positions returned from the gesture detector
bool isWithinTarget(x, y)

 if (x > x1 && x < x2 && y > y1 && y < y2) 
   // The pointer is within the target widget
   // Perform required action
   // Rebuild widget tree if necessary
   return true;
 
 return false;
 

【讨论】:

是的。但是,当您在父小部件中有很多子小部件时,这可能无法有效地检查哪个是 hovored。【参考方案6】:

很遗憾,您不能为此使用GestureDetecture,而必须使用MouseRegion

我正在使用answer 的想法,但我会更正它,因为它不起作用(对我来说)。 答案使用了PointerDetails,它对我有用。 我将使用PointerEvent

// inside your current widget
class _MyHoverableWidgetState extends State<MyHoverableWidget>

        // some previous code of your class //


        // define a class variable to store the current state of your mouse pointer
        bool amIHovering = false;

        // store the position where your mouse pointer left the widget
        Offset exitFrom = Offset(0,0);
    
        return MouseRegion(
            // callback when your mouse pointer enters the underlying widget
            // here you have to use 'PointerEvent'
            onEnter: (PointerEvent details) => setState(() => amIHovering = true),
            
            // callback when your mouse pointer leaves the underlying widget
            onExit: (PointerEvent details) => setState(()  
                amIHovering = false;
                // storing the exit position
                exitFrom = details.localPosition; // You can use details.position if you are interested in the global position of your pointer.
            ),

            // your underlying widget, can be anything
            child: Container(
                width: 200,
                height: 200,
                child: Center(
                    child:Text(amIHovering ? "Look mom, I'm hovering" : "I exited from: $exitFrom"),
                ), 
            ),
        );

    

【讨论】:

我今天发现,你也可以使用内置悬停功能的InkWell Widget!【参考方案7】:

Inkwell 小部件可以做到这一点。您只需要将您的小部件包裹在它周围。您可以用 Inkwell 替换 Gesture Detector。示例代码如下:

InkWell(
      onHover: (value)
      
        //Do something
      ,
        onTap: ()
      
        //Do something
      ,
      child: Container(),

)

【讨论】:

以上是关于如何检测 GestureDetector 是不是悬停在 Flutter 中?的主要内容,如果未能解决你的问题,请参考以下文章

Android使用GestureDetector进行手势检测

Android使用GestureDetector进行手势检测

Flutter web GestureDetector:检测鼠标滚轮事件

GestureDetector手势检测

如何检测用户是不是开始垂直滚动 Listview.builder?

android 判断左右滑动,上下滑动的GestureDetector简单手势检测