简体   繁体   English

Flutter-GestureDetector 不适用于堆栈中的容器

[英]Flutter- GestureDetector not working with containers in stack

I have two containers in a stack and both containers have GestureDetector.The OnTap for the first container is working fine but it's not working with another container.我有两个容器在一个堆栈中,两个容器都有 GestureDetector。第一个容器的 OnTap 工作正常,但它不适用于另一个容器。 The first container is the image and the second one is the green background aligned partially over the first container.第一个容器是图像,第二个是在第一个容器上部分对齐的绿色背景。

new Stack(
            alignment: Alignment(0.0, 1.44),
            children: <Widget>[
              GestureDetector(
                onTap: () => _openImage(context),
                child: Container(
                  width: 340.0,
                  foregroundDecoration: new BoxDecoration(
                      color: Color.fromRGBO(155, 85, 250, 0.55)),
                  height: 240.0,
                  child: FadeInImage.assetNetwork(
                    placeholder: 'assets/dimlight.png',
                    image: post.imageUrl,
                    fit: BoxFit.cover,
                  ),
                ),
              ),
              new GestureDetector(
                child: new Container(
                  color: Colors.green,
                  child: Row(
                    mainAxisSize: MainAxisSize.max,
                    children: <Widget>[
                      SizedBox(width: 7.0),
                      CircleAvatar(
                        backgroundImage: 
                           new AssetImage("assets/boy.png")
                        radius: 30.0,
                      ),
                      SizedBox(
                        width: 7.0,
                      ),
                      Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: <Widget>[
                          new SizedBox(
                            height: 20.0,
                          ),
                          Text(
                            post.user.name,
                            style: TextStyle(fontWeight: FontWeight.bold),
                          ),
                          Text(
                            getTimeString(post.timestamp.toString()),
                            style: TextStyle(
                                color: Colors.grey, fontSize: 10.0),
                          ),
                        ],
                      ),
                      SizedBox(
                        width: 20.0,
                      ),
                    ],
                  ),
                ),
                onTap: () => _navigateToDetails(context),
              )
            ],
          )

Layout Screenshot布局截图

在此处输入图片说明

尝试将GestureDetectorbehavior属性设置为HitTestBehavior.translucent

使用InkWell而不是GestureDetector解决了我的问题。

For me it was an issue with items overflowing outside a Stack , with clipBehavior: Clip.none .对我来说,这是一个项目在Stack外溢出的问题,带有clipBehavior: Clip.none

In that case the item is visible but not touchable.在这种情况下,该项目可见但不可触摸。 So I updated my layout to remove the clipBehavior: Clip.none on my Stack and the GestureDetector started working.所以我更新了我的布局以删除我的Stack上的clipBehavior: Clip.none并且GestureDetector开始工作。 🎉 🎉

In my case I had a CustomPainter inside the stack.就我而言,我在堆栈中有一个 CustomPainter。 Nothing of the above was working, until I gave the CustomerPainter a size.在我给 CustomerPainter 一个大小之前,以上都没有奏效。 It was showing without explicitly giving a size, but no tap events were triggered:它在没有明确给出大小的情况下显示,但没有触发点击事件:

Container(
      child: CustomPaint(
    size: Size(30, 30),
    painter: RecordingButton(30),
  ))

您应该尝试使用 AbsorbPointer 包装您的 Container。

i think that your widgets are overlapping each other and that the causing a problem.我认为您的小部件彼此重叠并且导致问题。 you can check it by wrapping your GestureDetector with container and provide color to get better understanding.你可以通过用容器包裹你的 GestureDetector 来检查它并提供颜色以获得更好的理解。

your code is not enough that's why i added following example may help you to understand more clearly.您的代码还不够,这就是为什么我添加以下示例可以帮助您更清楚地理解。

swap the position of GestureDetector in example and you can found that in first case it prints only second and in other case if you click in above part then it prints first to.在示例中交换 GestureDetector 的位置,您会发现在第一种情况下它只打印第二个,在其他情况下,如果您单击上面的部分,则它首先打印到。

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Firebase Auth Demo',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: new Card(
        margin: EdgeInsets.all(40.0),
        child: new Column(
          mainAxisSize: MainAxisSize.max,
          children: <Widget>[
            GestureDetector(
              onTap: () => print("first container"),
              child: Container(
                width: 340.0,
                foregroundDecoration: new BoxDecoration(
                    color: Color.fromRGBO(155, 85, 250, 0.0)),
                height: 240.0,
                child: FadeInImage.assetNetwork(
                  placeholder: 'images/p1.png',
                  image:
                  "https://www.straitstimes.com/sites/default/files/styles/article_pictrure_780x520_/public/articles/2016/06/15/ST_20160615_LLIMH_2368135.jpg?itok=8Dggu2PM&timestamp=1465926004",
                  fit: BoxFit.cover,
                ),
              ),
            ),
            new GestureDetector(
              child: new Container(
                foregroundDecoration: BoxDecoration(
                    color: Color.fromRGBO(155, 85, 250, 0.4)),
                child: Row(
                  mainAxisSize: MainAxisSize.max,
                  children: <Widget>[
                    SizedBox(width: 7.0),
                    CircleAvatar(
                      backgroundImage: new AssetImage("images/p2.jpg"),
                      radius: 30.0,
                    ),
                    SizedBox(
                      width: 7.0,
                    ),
                    Expanded(
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: <Widget>[
                          new SizedBox(
                            height: 20.0,
                          ),
                          Text(
                            "sfvgefbv",
                            style: TextStyle(fontWeight: FontWeight.bold),
                          ),
                          Text(
                            "sfvmsfkv",
                            style: TextStyle(
                                color: Colors.grey, fontSize: 10.0),
                          ),
                        ],
                      ),
                    ),
                    new Container(
                      alignment: AlignmentDirectional.centerEnd,
//            todo add here check if not logged in then ask to
                      child: Row(
                        mainAxisSize: MainAxisSize.min,
                        mainAxisAlignment: MainAxisAlignment.start,
                        children: <Widget>[
                          IconButton(
                              icon: Icon(
                                Icons.comment,
                                color: Colors.green,
                              ),
                              onPressed: () => print("message click")),
                          Text(
                            "2",
                            style: TextStyle(
                              color: Colors.green,
                            ),
                          ),
                          SizedBox(
                            width: 10.0,
                          )
                        ],
                      ),
                    ),
                  ],
                ),
              ),
              onTap: () => print("this is second container"),
            ),
            new Expanded(
              child: Container(
                padding: EdgeInsets.all(10.0),
                child: Column(
                  children: <Widget>[
                    Text(
                      "fsvkmfskbnmkffvberk",
                      style: TextStyle(
                          color: Colors.green, fontWeight: FontWeight.bold),
                    ),
                    new Text(
                      "svklmfslkbnernkjrnvkrwjnvrw",
                      maxLines: 6,
                      overflow: TextOverflow.ellipsis,
                    ),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Because of stack ..There are some widget on your GestureDetector .由于stack ..您的GestureDetector上有一些widget

Solution:解决方案:

Stack(
        children: <Widget>[
              ...//Other widgets,
              GestureDetector()
        ]

对于其他人来到这篇文章,另一个可能导致此问题的原因是层次结构更高的 AbsorbPointer。

Another GestureDetector in the BuildContext tree BuildContext 树中的另一个 GestureDetector

Ok on my side it was quite stupid but since it may happens to many of us I will explain:好吧,在我看来,这很愚蠢,但由于我们许多人可能会发生这种情况,我将解释:

My build context (simplified for the example) tree was this way:我的构建上下文(为示例简化)树是这样的:

Widget build(BuildContext context) {

return (...) (
    child: GestureDetector(
        onTap: () => _myFunction(),
        child: Container(
            height: 64.0,
            width: 128.0,
            child: (...)

Seems legit right?看起来合法吗? But then I inspected into more details the bottom of my tree:但后来我检查了树底部的更多细节:

(...)
        onTap: () => _myFunction(),
        child: Container(
            height: 64.0,
            width: 128.0,
            child: TheSourceOfEvil() // <-- whoopsie!

Quickly inspected TheSourceOfEvil to find out that the culprit was in fact ANOTHER GestureDetector has a child, that I had not yet implemented onTap: () => {}, :快速检查 TheSourceOfEvil 发现罪魁祸首实际上是另一个 GestureDetector有一个孩子,我还没有实现onTap: () => {}, :

Widget TheSourceOfEvil( {

return (...) (
    child: GestureDetector(
        onTap: () => {}, // override previous GestureDetector
        child: Container(
            child: (...);

Got rid of it and it instantly fixed my puzzling issue.摆脱它,它立即解决了我令人费解的问题。 I hope it will help!我希望它会有所帮助!

If your are using GoogleMap widget and want to add a searchfield/textfield you should be aware that the map widget is consuming your gestures.如果您正在使用 GoogleMap 小部件并想要添加搜索字段/文本字段,您应该知道地图小部件正在消耗您的手势。 I do something like this:我做这样的事情:

final FocusNode _focusNode = new FocusNode();

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      behavior: HitTestBehavior.translucent,
      onTap: () {            
        print("tap");
        if (_focusNode.hasPrimaryFocus) {
          _focusNode.unfocus();
          rebuildAfterFocusChange();
        }
      },
      child: Stack(children: [
        AbsorbPointer(absorbing: _focusNode.hasPrimaryFocus, child: StoreMapView()),
        showSearchField(model),
      ]),
    );
  }

Widget showSearchField(StoreFinderViewModel model) {
    return SafeArea(
      child: Padding(
        padding: const EdgeInsets.only(left: 8.0, right: 8.0, top: 12.0),
        child: TextField(
          onTap: () {
            rebuildAfterFocusChange();
          },
          onSubmitted: (String input) {
            rebuildAfterFocusChange();
            // do other stuff
            });
          },
          focusNode: _focusNode,
        ),
      ),
    );
  }

  void rebuildAfterFocusChange() {
    setState(() {});
  }

I am using the AbsorbPointer widget to absorb the clicks/taps, but ONLY if my textfield has the focus.我正在使用 AbsorbPointer 小部件来吸收点击/点击,但前提是我的文本字段具有焦点。 I call my rebuildAfterFocusChange();我打电话给我的 rebuildAfterFocusChange(); if I tap on my "Searchfield", use the onsubmit method of the textfield to trigger a search in my backend and after I unfocus my textfield.如果我点击我的“搜索字段”,请使用文本字段的 onsubmit 方法在我的后端触发搜索,并在我取消聚焦我的文本字段之后。

Also consider Listener widget.还要考虑Listener小部件。 It helped me.它帮助了我。
https://api.flutter.dev/flutter/widgets/Listener-class.html https://api.flutter.dev/flutter/widgets/Listener-class.html
Example:例子:

Listener(
    onPointerDown: (_) {}, // onTapDown
    onPointerUp: (_) => {}, // onTapUp
    child: Container(),
)

Okay here's the deal, I just changed the position of the widgets.好的,这是交易,我只是改变了小部件的位置。 In Stack Everything is like a Tree index.在堆栈中,一切都像一个树索引。

Stack Parent
  └ Child One    [Far Back]
  └ Child Two
  └ Child Three  [Top Front]

My Code:我的代码:

     return Stack(
              children: [
                accountInfo(),   // this is not clickable
                chatMessages(),
                typingArea(),
              ],
            ),

I just changes the sequence我只是改变了顺序

    return Stack(
              children: [
                chatMessages(),
                typingArea(),
                accountInfo(), // Now this is clickable by any of onTap Event ad
              ],
            ),

I see that you are calling the callback method instead of assigning it to onTap property of GestureDetector widget.我看到您正在调用回调方法,而不是将其分配给 GestureDetector 小部件的 onTap 属性。 Pass the name of the method don't call it there.传递方法的名称不要在那里调用它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM