You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 18:15:41