You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Flutter自定义ListView在iOS可正常滚动但Android无法滚动问题排查求助

问题分析与解决方案

嘿,我遇到过类似的Flutter跨平台滚动适配问题,咱们来一步步拆解你的情况:

问题根源

你的代码里有两个关键点导致了Android上的滚动失效:

  1. 外层SingleChildScrollView的滚动设置:你给它加了NeverScrollableScrollPhysics(),在Android的手势识别逻辑里,父组件的不可滚动设置会直接拦截子组件的滚动手势(iOS的手势优先级处理不同,所以能正常滚动)。
  2. 内层ListView.buildershrinkWrap: true:这个属性会让ListView的高度等于所有列表项的总高度,相当于把整个列表“展开”了,没有给它一个固定的可滚动视口,Android系统无法识别这是一个需要滚动的区域。

而BottomSheet里能正常滚动,是因为BottomSheet的默认布局自带了合适的滚动视口,并且手势处理不会拦截子组件的滚动事件,所以两边都能正常工作。

修复方案(推荐第一种)

方案一:移除外层SingleChildScrollView(更符合你的需求)

既然你只需要内层的星座列表滚动,外层标题是固定的,完全不需要整个页面滚动。修改代码如下:

修改OnBoardingScreen的布局

class OnBoardingScreen extends StatelessWidget {
 // final _dataAssetController = Get.find<DataAsset>();
 @override
 Widget build(BuildContext context) {
 return Scaffold(
 body: Container(
 width: double.infinity,
 decoration: BoxDecoration(
 image: DecorationImage(
 fit: BoxFit.cover,
 image: AssetImage('images/ss.jpg'),
 ),
 ),
 child: SafeArea(
 child: Padding(
 padding: const EdgeInsets.only(left: 15.0, top: 25.0),
 child: Column(
 crossAxisAlignment: CrossAxisAlignment.start,
 children: [
 ///---------------------- Title
 Text(
 'Your',
 style: TextStyle(
 fontSize: 30.0,
 fontWeight: FontWeight.bold,
 color: Colors.white,
 ),
 ),
 Text(
 'Star Sign?',
 style: TextStyle(
 fontSize: 45.0,
 fontFamily: 'FredokaOne',
 letterSpacing: 2.0,
 color: _dataAssetController.mainColor,
 ),
 ),
 SizedBox(height: 15.0),
 ///---------------------- Zodiac List: 用Expanded让列表占据剩余屏幕空间
 Expanded(
 child: ZodiacListWidget(),
 ),
 ],
 ),
 ),
 ),
 ),
 );
 }
}

修改ZodiacListWidget
去掉shrinkWrap: true,因为现在列表有了Expanded提供的固定视口,不需要自适应内容高度:

class ZodiacListWidget extends StatelessWidget {
 // final _dataAssetController = Get.find<DataAsset>();
 // final _zodiacController = Get.find<ZodiacApiController>();
 @override
 Widget build(BuildContext context) {
 return Container(
 child: ListView.builder(
 // 移除shrinkWrap: true
 itemCount: _dataAssetController.zodiacList.length,
 itemBuilder: (BuildContext context, index) {
 // 保持原来的itemBuilder代码不变
 return Padding(
 padding: EdgeInsets.symmetric(horizontal: 8.0),
 child: Card(
 color: Colors.grey[800],
 shape: RoundedRectangleBorder(
 borderRadius: BorderRadius.circular(15.0),
 ),
 child: ListTile(
 title: Padding(
 padding: EdgeInsets.only(left: 16.0),
 child: Text(
 _dataAssetController.zodiacList[index],
 style: TextStyle(
 color: Colors.grey[100],
 fontSize: 25.0,
 fontWeight: FontWeight.bold,
 ),
 ),
 ),
 subtitle: Padding(
 padding: EdgeInsets.only(left: 15.0),
 child: Text(
 _dataAssetController.zodiacDateRangeList[index],
 style: TextStyle(
 color: Colors.grey[500],
 fontSize: 18.0,
 ),
 ),
 ),
 leading: CircleAvatar(
 radius: 20.0,
 backgroundColor: Colors.grey[800],
 child: SvgPicture.asset(
 _dataAssetController.zodiacSVGList[index],
 color: _dataAssetController.mainColor,
 ),
 ),
 trailing: IconButton(
 icon: GetBuilder<ZodiacApiController>(
 builder: (_zController) => Icon(
 Icons.adjust,
 size: 25.0,
 color: _dataAssetController.zodiacList[index] == _zController.zodiacSign
 ? _dataAssetController.mainColor
 : Colors.grey[300],
 ),
 ),
 onPressed: () {
 _zodiacController.changeZodiac(index);
 _zodiacController.onBoarding != null
 ? null
 : Get.defaultDialog(
 title: '',
 titleStyle: TextStyle(
 fontSize: 0.0,
 ),
 middleText: _zodiacController.zodiacSign!,
 middleTextStyle: TextStyle(
 fontSize: 30.0,
 fontWeight: FontWeight.bold,
 ),
 textConfirm: 'Confirm',
 confirmTextColor: Colors.white,
 onConfirm: () {
 _zodiacController.onBoarding != null
 ? null
 : _zodiacController.changeOnBoarding();
 Navigator.pushReplacement(
 context,
 MaterialPageRoute(
 builder: (context) => HomeScreen(),
 ),
 );
 },
 textCancel: 'Back',
 cancelTextColor: Colors.blueAccent,
 onCancel: () => Navigator.pop(context),
 );
 },
 ),
 ),
 ),
 );
 },
 ),
 );
 }
}

方案二:如果必须保留外层SingleChildScrollView

给内层ListView添加强制滚动的物理属性,同时给它设置固定高度:

class ZodiacListWidget extends StatelessWidget {
 // final _dataAssetController = Get.find<DataAsset>();
 // final _zodiacController = Get.find<ZodiacApiController>();
 @override
 Widget build(BuildContext context) {
 return Container(
 // 根据你的标题高度调整这个数值,确保列表有合适的滚动空间
 height: MediaQuery.of(context).size.height - 200,
 child: ListView.builder(
 shrinkWrap: true,
 // 强制Android识别滚动手势
 physics: const AlwaysScrollableScrollPhysics(),
 itemCount: _dataAssetController.zodiacList.length,
 itemBuilder: (BuildContext context, index) {
 // 保持原来的itemBuilder代码不变
 return Padding(
 padding: EdgeInsets.symmetric(horizontal: 8.0),
 child: Card(
 color: Colors.grey[800],
 shape: RoundedRectangleBorder(
 borderRadius: BorderRadius.circular(15.0),
 ),
 child: ListTile(
 title: Padding(
 padding: EdgeInsets.only(left: 16.0),
 child: Text(
 _dataAssetController.zodiacList[index],
 style: TextStyle(
 color: Colors.grey[100],
 fontSize: 25.0,
 fontWeight: FontWeight.bold,
 ),
 ),
 ),
 subtitle: Padding(
 padding: EdgeInsets.only(left: 15.0),
 child: Text(
 _dataAssetController.zodiacDateRangeList[index],
 style: TextStyle(
 color: Colors.grey[500],
 fontSize: 18.0,
 ),
 ),
 ),
 leading: CircleAvatar(
 radius: 20.0,
 backgroundColor: Colors.grey[800],
 child: SvgPicture.asset(
 _dataAssetController.zodiacSVGList[index],
 color: _dataAssetController.mainColor,
 ),
 ),
 trailing: IconButton(
 icon: GetBuilder<ZodiacApiController>(
 builder: (_zController) => Icon(
 Icons.adjust,
 size: 25.0,
 color: _dataAssetController.zodiacList[index] == _zController.zodiacSign
 ? _dataAssetController.mainColor
 : Colors.grey[300],
 ),
 ),
 onPressed: () {
 _zodiacController.changeZodiac(index);
 _zodiacController.onBoarding != null
 ? null
 : Get.defaultDialog(
 title: '',
 titleStyle: TextStyle(
 fontSize: 0.0,
 ),
 middleText: _zodiacController.zodiacSign!,
 middleTextStyle: TextStyle(
 fontSize: 30.0,
 fontWeight: FontWeight.bold,
 ),
 textConfirm: 'Confirm',
 confirmTextColor: Colors.white,
 onConfirm: () {
 _zodiacController.onBoarding != null
 ? null
 : _zodiacController.changeOnBoarding();
 Navigator.pushReplacement(
 context,
 MaterialPageRoute(
 builder: (context) => HomeScreen(),
 ),
 );
 },
 textCancel: 'Back',
 cancelTextColor: Colors.blueAccent,
 onCancel: () => Navigator.pop(context),
 );
 },
 ),
 ),
 ),
 );
 },
 ),
 );
 }
}

这样修改后,Android和iOS上的列表都能正常滚动了。

内容的提问来源于stack exchange,提问作者Raj A

火山引擎 最新活动