Flutter使用smooth_page_indicator报错:Unsupported operation: Infinity or NaN toInt
Flutter smooth_page_indicator 报错:Unsupported operation: Infinity or NaN toInt 解决思路
问题说明
开发一款展示图片列表的Flutter应用,通过API获取图片数据,使用smooth_page_indicator 1.0.0+2组件配合PageView实现轮播指示器时,触发如下渲染异常:
======== Exception caught by rendering library ===================================================== The following UnsupportedError was thrown during paint(): Unsupported operation: Infinity or NaN toInt The relevant error-causing widget was: SmoothPageIndicator SmoothPageIndicator:file:///C:/Users/**********/widgetImage.dart:96:30 When the exception was thrown, this was the stack: #0 double.toInt (dart:core-patch/double.dart) #1 WormPainter.paint (package:smooth_page_indicator/src/painters/worm_painter.dart:21:40) #2 RenderCustomPaint._paintWithPainter (package:flutter/src/rendering/custom_paint.dart:571:13) #3 RenderCustomPaint.paint (package:flutter/src/rendering/custom_paint.dart:613:7) #4 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2796:7) #5 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:239:13) #6 RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:144:15) #7 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2796:7)
完整实现代码:
class _WidgetImageState extends State<WidgetImage> { List<ImageTopicModel> _ListData = []; List<ImageTopicModel> _ListDataDisplay = []; @override void initState() { Api().then((value) { if (this.mounted) { setState(() { _ListData.addAll(value); _ListDataDisplay = _ListData; }); } }); super.initState(); } PageController _pageController = PageController(); int page = 0; void onPageViewChange(int _page) { page = _page; // setState(() {}); } @override Widget build(BuildContext context) { return Container( width: double.infinity, height: 400, child: Stack(children: <Widget>[ Stack( children: <Widget>[ Container( width: double.infinity, height: 400, child: PageView.builder( physics: BouncingScrollPhysics(), controller: _pageController, onPageChanged: onPageViewChange, itemCount: _ListDataDisplay.length, itemBuilder: (BuildContext context, int index) { return Container( child: Column(children: <Widget>[ InkWell( child: CachedNetworkImage( imageUrl: "${_ListDataDisplay[index].image}", width: double.infinity, height: 400, fit: BoxFit.cover, errorWidget: (context, url, error) => Icon(Icons.error), ), onTap: () { Navigator.push(context, MaterialPageRoute( builder: (context) { return ShowImageOfAd( "${_ListDataDisplay[index].image}"); })); }), ]), ); }), ), Container( child: Align( alignment: Alignment.bottomCenter, child: Container( height: 40, decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Colors.black.withOpacity(0.0), Colors.black.withOpacity(0.5) ])), child: Align( alignment: Alignment.center, child: SmoothPageIndicator( controller: _pageController, // PageController count: _ListDataDisplay.length, axisDirection: Axis.horizontal, effect: WormEffect( dotWidth: 9.0, dotHeight: 9.0, dotColor: Colors.black26, activeDotColor: Colors.white, ), onDotClicked: (index) {}), ), ), )), ], ), ]), ); } }
错误原因
从异常栈可以看出,错误发生在WormPainter的绘制逻辑中。当API数据未加载完成时,_ListDataDisplay是空列表,此时SmoothPageIndicator的count参数为0。组件内部计算指示器位置时会出现除以0的操作,导致结果为NaN或Infinity,调用toInt()方法时就会抛出该异常。
解决思路
1. 数据加载完成前隐藏指示器
在build方法中判断列表长度,只有当数据加载完成(列表长度大于0)时才渲染SmoothPageIndicator,否则渲染空组件:
child: Align( alignment: Alignment.center, child: _ListDataDisplay.length > 0 ? SmoothPageIndicator( controller: _pageController, count: _ListDataDisplay.length, axisDirection: Axis.horizontal, effect: WormEffect( dotWidth: 9.0, dotHeight: 9.0, dotColor: Colors.black26, activeDotColor: Colors.white, ), onDotClicked: (index) {}) : SizedBox.shrink(), // 空占位符 ),
2. 全局加载状态处理
在数据未加载完成时,整个轮播区域显示加载组件(比如CircularProgressIndicator),避免空列表导致的PageView和指示器异常:
@override Widget build(BuildContext context) { if (_ListDataDisplay.isEmpty) { return Container( width: double.infinity, height: 400, child: Center(child: CircularProgressIndicator()), ); } return Container( // 原有的轮播布局代码 ); }
3. 优化数据赋值逻辑
原代码中_ListDataDisplay = _ListData;是引用赋值,后续修改_ListData会直接影响_ListDataDisplay,建议改为深拷贝:
setState(() { _ListData.addAll(value); _ListDataDisplay = List.from(_ListData); // 深拷贝创建新列表 });
内容的提问来源于stack exchange,提问作者M Al
相关产品推荐
相关产品推荐

