这是按钮和堆栈的一个已知困难,我建议任何有此类问题的人看看Github 上的讨论 https://github.com/flutter/flutter/issues/27587.
TL;DR:
翻译小部件时,您可以点击的区域由两部分组成:
- 父控件的区域
- 子项的区域(此处为 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"),
),
),
),
),
在这里您可以点击父容器中的任意位置。
为您提供解决方案
你实际上想要一些不同的东西:除了按钮之外的任何东西都是可点击的。为此,您需要:
- GestureDetector 是可点击区域的父级
- 带有 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"),
),
),
),
),
)
],
),
);
}
}
为什么这有效
如前所述,父级是青色容器,该容器中的任何区域都将使按钮可单击。
此外,在此容器顶部添加一个 GestureDetector 使我们能够捕获此容器内的任何点击。
最后,当您单击时,会发生以下情况:
- 在青色容器之外,什么也没有发生。
- Inside the cyan Container
- 在按钮外部,GestureController 捕获轻击并使按钮移动
- 在按钮内部,Button 捕获点击,不执行任何操作(空方法),并将此点击标记为已处理这导致它不会在树上冒泡因此 GestureController 什么也得不到,也什么也没有发生。
希望这可以帮助您和其他人理解所有这些工作的棘手方式。一旦你拥抱它,它就会变得很美丽;)