FlatButton 翻译后 Flutter onPressed 不起作用

Flutter onPressed not works after FlatButton translate

我在使用 ScrollViewTransform 时遇到了一些事件处理问题。布局结构是这样的,ScrollViewTransform存在于Stack.

里面

我想让ScrollViewContainer(Colors.cyan)中滚动到FlatButton外时滚动,事件可以穿透到ScrollView。

点击FlatButton onPress to work。实际上,点击FlatButton两次后,无论点击初始位置还是当前位置,都不再移动。 FlatButton控件在尺寸范围内离开初始位置,不再检测到点击事件,但我没看懂。代码如下:

class EventListener extends StatefulWidget {
  @override
  _EventListenerState createState() => _EventListenerState();
}

class _EventListenerState extends State<EventListener> {

  Offset offset = Offset(0, 0);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("EventListener"),
      ),
      body: Stack(
        children: <Widget>[
          SingleChildScrollView(
            child: Column(
              children: <Widget>[
                Container(
                  color: Colors.red,
                  height: 200,
                ),
                Container(
                  color: Colors.teal,
                  height: 300,
                ),
                Container(
                  color: Colors.orange,
                  height: 400,
                )
              ],
            ),
          ),
          Container(
            color: Colors.cyan,
            width: double.infinity,
            height: 400,
            alignment: Alignment.center,
            child: SizedBox(
              width: 100,
              height: 100,
              child: Transform.translate(
                offset: offset,
                child: FlatButton(
                  color: Colors.orange,
                  onPressed: () {
                    setState(() {
                      offset += Offset(50, 50);
                    });
                    print('click !');
                  },
                  child: Text("translate"),
                ),
              ),
            ),
          )
        ],
      ),
    );
  }
}

这是 Buttons and Stacks 的一个已知问题,我建议遇到此类问题的任何人查看 this discussion on Github

TL;DR:

翻译小部件时,您可以点击的区域由两部分组成:

  1. 父控件的面积
  2. 子区域(这里的Flatbutton)

见下图:

通常的解决方法:

正在扩展父级的大小。

这给了我们这样的东西:

Container( 
  width: double.infinity,
  height: 400,
  child: Transform.translate(
    offset: offset,
    child: SizedBox(
      width: 100,
      height: 100,
      child: FlatButton(
        onPressed: () => print('tap button'),
        child: Text("translate"),
      ),
    ),
  ),
),

在这里您可以点击父容器中的任意位置。

为您解决

您实际上想要一些不同的东西:除了按钮之外的任何东西都是可点击的。为此你需要:

  1. GestureDetector 是可点击区域的父级
  2. 带有不执行任何操作的 onPressed 方法的 FlatButton

如果我们只希望蓝色容器可点击,那么这是最终代码:

import 'package:flutter/material.dart';

main() => runApp(MaterialApp(
  home: EventListener(),
));

class EventListener extends StatefulWidget {
  @override
  _EventListenerState createState() => _EventListenerState();
}

class _EventListenerState extends State<EventListener> {
  Offset offset = Offset(0, 0);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("EventListener"),
      ),
      body: Stack(
        children: <Widget>[
          SingleChildScrollView(
            child: Column(
              children: <Widget>[
                Container(
                  color: Colors.red,
                  height: 200,
                ),
                Container(
                  color: Colors.teal,
                  height: 300,
                ),
                Container(
                  color: Colors.orange,
                  height: 400,
                )
              ],
            ),
          ),
          GestureDetector(
            onTap: () {
              setState(() {
                offset += Offset(50, 50);
              });
            },
            child: Container(
              width: double.infinity,
              height: 400,
              color: Colors.cyan,
              alignment: Alignment.center,
              child: Transform.translate(
                offset: offset,
                child: SizedBox(
                  width: 100,
                  height: 100,
                  child: FlatButton(
                    color: Colors.orange,
                    onPressed: () {},
                    child: Text("translate"),
                  ),
                ),
              ),
            ),
          )
        ],
      ),
    );
  }
}

为什么这有效

如前所述,父容器是青色容器,此容器中的任何区域都将使按钮可点击。

此外,在此 Container 之上添加 GestureDetector 使我们能够捕获此 Container 内的任何点击。

所以最后这就是当你点击时会发生什么,如果你点击:

  1. 在青色Container之外,没有任何反应。
  2. 青色容器内
    1. 在按钮外部,GestureController 捕捉点击并使按钮移动
    2. 在按钮内部,Button 捕捉点击,不对其执行任何操作(空方法),并将此点击标记为已处理这会导致它不会在树中冒泡因此 GestureController 什么也得不到,什么也没有发生。

希望这可以帮助您和其他人理解所有这些工作的棘手方式。一旦你拥抱它,它就会变得很美 ;)

尽管我做了上面所说的事情,但它对我不起作用。所以我调试了几个小时,找到了解决方案。我希望它对某人有所帮助。

如果您的父窗口小部件是 Column/Row/Wrap 并且如果您将窗口小部件转换到另一个窗口小部件的顶部,出于某种原因手势检测器将不起作用。因此,您需要删除 Column/Row/Wrap 小部件才能使其正常工作。

this blue button isn't clickable on red area, bottom side clickable

示例代码:

      SingleChildScrollView(   
            controller: _scrollViewController,
            child: Column(children: [
             Container(
                height: 500,
                color: Colors.red,
              ),

              Wrap(
                children: [
                  FractionalTranslation(
                      translation: Offset(0.0, -0.5),
                      child: FlatButton(
                        child: Container(
                          color: Colors.blue,
                          height: 100,
                        ),
                        onPressed: () {
                          print("INGA");
                        },
                      )),
                ],
              ),])

移除 Wrap 小部件后,按钮再次变为完全可点击。