Flutter中使用ListView Builder组件时返回按钮失效问题
问题:添加ListView Builder后返回按钮失效
我编写了一段Flutter代码用于展示返回按钮、文本及ListView Builder组件。移除ListView Builder组件时返回按钮可正常工作,但添加该组件后返回按钮便失效,急需解决此问题。以下是页面代码:
import 'package:flutter/material.dart'; import 'package:workout_app/Screens/Components/Sign_Up_Screens/screen2.dart'; class SingleSelectListViewWithLogo extends StatefulWidget { final List<String> items; const SingleSelectListViewWithLogo({Key? key, required this.items}) : super(key: key); @override _SingleSelectListViewWithLogoState createState() => _SingleSelectListViewWithLogoState(); } class _SingleSelectListViewWithLogoState extends State<SingleSelectListViewWithLogo> { int? selectedIndex; void returnScreen(context) { print('returning'); Navigator.of(context).pushReplacement( MaterialPageRoute( fullscreenDialog: true, builder: (context) => screen2(), ), ); } bool nextValid = false; @override Widget build(BuildContext context) { Size size = MediaQuery.of(context).size; return Material( child: Container ( decoration: const BoxDecoration(color: Colors.grey), height: size.height, width: double.infinity, child: Stack( children: <Widget> [ Positioned( top: size.height * .06, left: size.width * .03, child: InkWell( onTap: () { returnScreen(context); }, child: Image.asset( alignment: Alignment.topLeft, "assets/images/back2.png", width: size.width * .07, ), ), ), Positioned( top: size.height * .09, left: size.width * .4, child: const Text( style: TextStyle(fontSize: 30, color: Color.fromARGB(255, 4, 3, 3)), 'Goals' ) ), Positioned( top: size.height * .15, left: size.width * .07, child: const Text( style: TextStyle(fontSize: 20, color: Color.fromARGB(255, 49, 48, 48)), 'What body type do you want to get?' ) ), Positioned( top: size.height * .26, left: size.width * .4, child: const Text( style: TextStyle(fontSize: 15, color: Color.fromARGB(255, 33, 31, 31)), 'Select 1' ) ), ListView.builder( itemCount: widget.items.length, itemBuilder: (context, index) { return GestureDetector( onTap: () { setState(() { selectedIndex = index; nextValid = true; }); }, child: Container( height: size.height * .15, decoration: BoxDecoration( color: selectedIndex == index ? Color.fromARGB(255, 40, 188, 72) : Color.fromARGB(255, 202, 195, 195), border: Border.all( color: selectedIndex == index ? Color.fromARGB(255, 16, 66, 37) : Colors.transparent, width: 3, ), borderRadius: BorderRadius.circular(10), ), padding: const EdgeInsets.symmetric(horizontal: 10), margin: EdgeInsets.fromLTRB(16, index == 0 ? MediaQuery.of(context).size.height * 0.265 : 0, 16, 8), child: Row( children: [ Flexible( child: Text(widget.items[index]), ) ], ), ), ); }, ), Positioned( top: size.height * .86, left: size.width * .1, child: SizedBox( width: size.width * .8, height: size.height * .08, child: ElevatedButton( style: ButtonStyle( backgroundColor: MaterialStateProperty.all<Color>(!nextValid ? Color.fromRGBO(69, 75, 85, 1) : Color.fromARGB(255, 0, 147, 246)), ), child: const Text('Continue', style: TextStyle(fontSize: 20), ), onPressed: () async { }, ), ), ), ] ) ) ); } }
问题原因
返回按钮失效是因为Stack布局中ListView的触摸区域覆盖了顶部的返回按钮。ListView默认会占满父容器的全部空间,且它的触摸事件优先级高于上层的Positioned元素,导致返回按钮的InkWell无法接收点击事件。
解决方案
重构布局结构,用Column替代Stack,让各组件按垂直方向排列,避免层级遮挡:
import 'package:flutter/material.dart'; import 'package:workout_app/Screens/Components/Sign_Up_Screens/screen2.dart'; class SingleSelectListViewWithLogo extends StatefulWidget { final List<String> items; const SingleSelectListViewWithLogo({Key? key, required this.items}) : super(key: key); @override _SingleSelectListViewWithLogoState createState() => _SingleSelectListViewWithLogoState(); } class _SingleSelectListViewWithLogoState extends State<SingleSelectListViewWithLogo> { int? selectedIndex; bool nextValid = false; void returnScreen(context) { print('returning'); Navigator.of(context).pushReplacement( MaterialPageRoute( fullscreenDialog: true, builder: (context) => screen2(), ), ); } @override Widget build(BuildContext context) { Size size = MediaQuery.of(context).size; return Scaffold( backgroundColor: Colors.grey, body: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 顶部返回按钮 Padding( padding: EdgeInsets.only(top: size.height * .06, left: size.width * .03), child: InkWell( onTap: () => returnScreen(context), child: Image.asset( "assets/images/back2.png", width: size.width * .07, ), ), ), // 标题 Center( child: Padding( padding: EdgeInsets.only(top: size.height * .03), child: const Text( 'Goals', style: TextStyle(fontSize: 30, color: Color.fromARGB(255, 4, 3, 3)), ), ), ), // 说明文本1 Padding( padding: EdgeInsets.only(top: size.height * .06, left: size.width * .07), child: const Text( 'What body type do you want to get?', style: TextStyle(fontSize: 20, color: Color.fromARGB(255, 49, 48, 48)), ), ), // 说明文本2 Center( child: Padding( padding: EdgeInsets.only(top: size.height * .11), child: const Text( 'Select 1', style: TextStyle(fontSize: 15, color: Color.fromARGB(255, 33, 31, 31)), ), ), ), // 中间可滚动列表 Expanded( child: ListView.builder( padding: EdgeInsets.fromLTRB(16, size.height * .02, 16, 8), itemCount: widget.items.length, itemBuilder: (context, index) { return GestureDetector( onTap: () { setState(() { selectedIndex = index; nextValid = true; }); }, child: Container( height: size.height * .15, margin: const EdgeInsets.only(bottom: 8), decoration: BoxDecoration( color: selectedIndex == index ? const Color.fromARGB(255, 40, 188, 72) : const Color.fromARGB(255, 202, 195, 195), border: Border.all( color: selectedIndex == index ? const Color.fromARGB(255, 16, 66, 37) : Colors.transparent, width: 3, ), borderRadius: BorderRadius.circular(10), ), padding: const EdgeInsets.symmetric(horizontal: 10), child: Align( alignment: Alignment.centerLeft, child: Text(widget.items[index]), ), ), ); }, ), ), // 底部按钮 Padding( padding: EdgeInsets.only(bottom: size.height * .07, left: size.width * .1, right: size.width * .1), child: SizedBox( width: double.infinity, height: size.height * .08, child: ElevatedButton( style: ButtonStyle( backgroundColor: MaterialStateProperty.all<Color>( !nextValid ? const Color.fromRGBO(69, 75, 85, 1) : const Color.fromARGB(255, 0, 147, 246) ), ), child: const Text( 'Continue', style: TextStyle(fontSize: 20), ), onPressed: () async {}, ), ), ), ], ), ); } }
修改说明
- 用
Scaffold+Column替代Stack,组件按垂直方向排列,彻底避免层级遮挡问题 - 顶部元素通过
Padding控制位置,不再依赖Positioned - ListView用
Expanded包裹,自动占满剩余空间,不会覆盖顶部和底部元素 - 调整了各元素的间距,保持原视觉效果
内容的提问来源于stack exchange,提问作者Promaster
相关产品推荐
相关产品推荐

