[英]Flutter- GestureDetector not working with containers in stack
我有两个容器在一个堆栈中,两个容器都有 GestureDetector。第一个容器的 OnTap 工作正常,但它不适用于另一个容器。 第一个容器是图像,第二个是在第一个容器上部分对齐的绿色背景。
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),
)
],
)
布局截图
尝试将GestureDetector
的behavior
属性设置为HitTestBehavior.translucent
。
使用InkWell
而不是GestureDetector
解决了我的问题。
对我来说,这是一个项目在Stack
外溢出的问题,带有clipBehavior: Clip.none
。
在这种情况下,该项目可见但不可触摸。 所以我更新了我的布局以删除我的Stack
上的clipBehavior: Clip.none
并且GestureDetector
开始工作。 🎉
就我而言,我在堆栈中有一个 CustomPainter。 在我给 CustomerPainter 一个大小之前,以上都没有奏效。 它在没有明确给出大小的情况下显示,但没有触发点击事件:
Container(
child: CustomPaint(
size: Size(30, 30),
painter: RecordingButton(30),
))
您应该尝试使用 AbsorbPointer 包装您的 Container。
我认为您的小部件彼此重叠并且导致问题。 你可以通过用容器包裹你的 GestureDetector 来检查它并提供颜色以获得更好的理解。
您的代码还不够,这就是为什么我添加以下示例可以帮助您更清楚地理解。
在示例中交换 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×tamp=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,
),
],
),
),
),
],
),
),
);
}
}
由于stack
..您的GestureDetector
上有一些widget
。
解决方案:
Stack(
children: <Widget>[
...//Other widgets,
GestureDetector()
]
对于其他人来到这篇文章,另一个可能导致此问题的原因是层次结构更高的 AbsorbPointer。
好吧,在我看来,这很愚蠢,但由于我们许多人可能会发生这种情况,我将解释:
我的构建上下文(为示例简化)树是这样的:
Widget build(BuildContext context) {
return (...) (
child: GestureDetector(
onTap: () => _myFunction(),
child: Container(
height: 64.0,
width: 128.0,
child: (...)
看起来合法吗? 但后来我检查了树底部的更多细节:
(...)
onTap: () => _myFunction(),
child: Container(
height: 64.0,
width: 128.0,
child: TheSourceOfEvil() // <-- whoopsie!
快速检查 TheSourceOfEvil 发现罪魁祸首实际上是另一个 GestureDetector有一个孩子,我还没有实现onTap: () => {},
:
Widget TheSourceOfEvil( {
return (...) (
child: GestureDetector(
onTap: () => {}, // override previous GestureDetector
child: Container(
child: (...);
摆脱它,它立即解决了我令人费解的问题。 我希望它会有所帮助!
如果您正在使用 GoogleMap 小部件并想要添加搜索字段/文本字段,您应该知道地图小部件正在消耗您的手势。 我做这样的事情:
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(() {});
}
我正在使用 AbsorbPointer 小部件来吸收点击/点击,但前提是我的文本字段具有焦点。 我打电话给我的 rebuildAfterFocusChange(); 如果我点击我的“搜索字段”,请使用文本字段的 onsubmit 方法在我的后端触发搜索,并在我取消聚焦我的文本字段之后。
还要考虑Listener
小部件。 它帮助了我。
https://api.flutter.dev/flutter/widgets/Listener-class.html
例子:
Listener(
onPointerDown: (_) {}, // onTapDown
onPointerUp: (_) => {}, // onTapUp
child: Container(),
)
好的,这是交易,我只是改变了小部件的位置。 在堆栈中,一切都像一个树索引。
Stack Parent
└ Child One [Far Back]
└ Child Two
└ Child Three [Top Front]
我的代码:
return Stack(
children: [
accountInfo(), // this is not clickable
chatMessages(),
typingArea(),
],
),
我只是改变了顺序
return Stack(
children: [
chatMessages(),
typingArea(),
accountInfo(), // Now this is clickable by any of onTap Event ad
],
),
我看到您正在调用回调方法,而不是将其分配给 GestureDetector 小部件的 onTap 属性。 传递方法的名称不要在那里调用它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.