如何让Flutter Stack组件外的图标具备可点击性?
问题原因与解决方案
你的问题出在Stack的布局尺寸没有覆盖到白色卡片的全部区域:
- Stack本身的高度只等于蓝色Container的
height值 - 你用
Positioned把白色卡片向上偏移了bottom: -height/2,导致卡片上半部分(黑色图标所在位置)超出了Stack的布局边界 - Flutter中组件的点击事件只会在自身布局范围内触发,超出的部分不会响应hitTest,所以图标点击无效
解决方法1:调整Stack尺寸覆盖整个卡片
给Stack设置minHeight,让它的高度足够包含白色卡片的全部区域。计算方式:白色卡片高度是height*1.2,向上偏移了height/2,所以Stack最小高度需要是 height + (height*1.2 - height/2) = height*1.7
修改后的代码:
Stack( clipBehavior: Clip.none, alignment: AlignmentDirectional.bottomCenter, // 添加minHeight确保Stack覆盖整个卡片 minHeight: height * 1.7, children: <Widget>[ Container( height: height, color: const Color(0xFF049DFE), ), Positioned( bottom: -height / 2, left: 16.0, right: 16.0, height: height * 1.2, child: Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(10.0), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(1), spreadRadius: 2, blurRadius: 5, offset: const Offset(0, 3), ), ], ), child: Padding( padding: const EdgeInsets.all(16.0), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Hey, $fname!', style: const TextStyle( fontWeight: FontWeight.w900, fontSize: 20, ), ), const Spacer(), TextButton( onPressed: () {}, child: Row( mainAxisSize: MainAxisSize.min, children: [ const Text( 'Add Money', style: TextStyle( fontSize: 12, ), ), const SizedBox(width: 5), Image.asset( 'assets/images/addmoney.png', width: 20, height: 20) ], ), ), ], ), SizedBox(height: height / 3.5), //balance Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( showBalance ? 'NGN236,600.00' : '***********', style: const TextStyle( fontWeight: FontWeight.w900, fontSize: 20, ), ), const Spacer(), TextButton( onPressed: () { setState(() { showBalance = !showBalance; }); }, child: showBalance ? const Icon(Icons.visibility) : const Icon(Icons.visibility_off), ), ], ), ], ), ), ), ), ], ),
解决方法2:用Transform.translate替代Positioned(更稳妥)
Positioned容易导致组件超出父布局边界,改用Transform.translate只是视觉上偏移卡片,组件的布局边界仍在父容器范围内,点击事件不会失效:
Column( children: [ Container( height: height, color: const Color(0xFF049DFE), ), Transform.translate( // 向上偏移height/2,和原Positioned效果一致 offset: Offset(0, -height / 2), child: Container( margin: const EdgeInsets.symmetric(horizontal: 16.0), height: height * 1.2, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(10.0), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(1), spreadRadius: 2, blurRadius: 5, offset: const Offset(0, 3), ), ], ), child: Padding( padding: const EdgeInsets.all(16.0), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Hey, $fname!', style: const TextStyle( fontWeight: FontWeight.w900, fontSize: 20, ), ), const Spacer(), TextButton( onPressed: () {}, child: Row( mainAxisSize: MainAxisSize.min, children: [ const Text( 'Add Money', style: TextStyle( fontSize: 12, ), ), const SizedBox(width: 5), Image.asset( 'assets/images/addmoney.png', width: 20, height: 20) ], ), ), ], ), SizedBox(height: height / 3.5), //balance Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( showBalance ? 'NGN236,600.00' : '***********', style: const TextStyle( fontWeight: FontWeight.w900, fontSize: 20, ), ), const Spacer(), TextButton( onPressed: () { setState(() { showBalance = !showBalance; }); }, child: showBalance ? const Icon(Icons.visibility) : const Icon(Icons.visibility_off), ), ], ), ], ), ), ), ), ], ),
内容的提问来源于stack exchange,提问作者Raphael Tunji
相关产品推荐
相关产品推荐

