Flutter Stack组件点击Container时触发末尾子节点onTap事件问题求助

问题原因
这是Flutter Stack组件的默认行为导致的,核心有两个触发点:
- Stack的子组件按书写顺序层叠,越靠后声明的子组件层级越高,会优先接收点击事件。如果上层组件没有主动透传点击,下层组件的点击事件会被直接拦截,所以你会看到只有排在最后的子组件的onTap能触发。
- 你当前代码里给Stack的子组件设置了
bottom: -170.0,导致这个子组件的大部分区域超出了Stack父容器(高度200)的边界。即便Stack设置了overflow: Overflow.visible只是让溢出的部分可见,Flutter默认的命中测试规则不会检测超出Stack自身尺寸的区域,所以溢出区域的点击事件本来就无法正常响应。
解决方案
方案1(最推荐,从结构层面解决问题)
把溢出Stack的白色圆角Container从Stack中移出,放在Stack所在的Column的下一个子节点,避免组件溢出的问题,点击事件自然恢复正常:
body: Container( color: Colors.white, child: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // 原灰色背景的Stack容器 Container( color: Color(0xffF0F0F0), height: 200, child: Stack( alignment: Alignment.center, children: [ // 这里放原来Stack里除了那个溢出的Positioned组件之外的内容,比如GestureDetector包裹的Image ], ), ), // 把原来Stack里的白色圆角Container移到这里,不需要加Positioned Container( transform: Matrix4.translationValues(0, -30, 0), // 用transform实现上移重叠的效果,替代原来的bottom负数值 padding: EdgeInsets.only(top: 40 , right: 10, left: 10), height: 250, decoration: BoxDecoration( color: Color(0xffFFFFFF), borderRadius: BorderRadius.circular(30), border: Border.all( width: 1, color: Colors.black, style: BorderStyle.solid, ), ), child: Column( children: [ Text('company', textAlign: TextAlign.center, style: TextStyle( fontSize: 24, color: Colors.black, ), ), Text("The number 2000"), RatingBar( rating: 3, icon:Icon(Icons.star,size:20,color: Colors.grey,), starCount: 5, spacing: 5.0, size: 20, isIndicator: false, allowHalfRating: true, onRatingCallback: (double value,ValueNotifier<bool> isIndicator){ print('Number of stars--> $value'); isIndicator.value=true; }, color: Colors.amber, ), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ sonItem(Icons.phone,"call us",Colors.green), sonItem(Icons.location_on_outlined,"location",Colors.red), sonItem(Icons.facebook,"FaceBook",Colors.blue), sonItem(Icons.add_ic_call_outlined,"whatsapp",Colors.green) ], ) ],), ) ], ), ), )
方案2(如果必须保留Stack内的溢出结构)
给sonItem里的GestureDetector添加behavior属性,同时如果有不需要响应点击的上层组件,套上IgnorePointer透传点击:
sonItem(dynamic icon ,String text,Color color){ return GestureDetector( behavior: HitTestBehavior.opaque, // 加上这行,保证点击区域被正确捕获 onTap: () { print("dddddddddddddddd"); }, child: Container( width: 70, height: 100, margin: EdgeInsets.all(2), padding: EdgeInsets.all(2), child: Column( children: [ Icon(icon ,color: color,), Text(text) ], ), ), ); }
如果有上层透明组件需要透传点击给下层,给上层组件套IgnorePointer:
IgnorePointer( ignoring: true, // 设为true的话,当前组件不会响应点击,点击会透传给下层组件 child: 你的上层组件, )
内容的提问来源于stack exchange,提问作者mhs
相关产品推荐
相关产品推荐

