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

Flutter请求数据时触发dotsCount must be superior to zero错误求助

问题:Flutter中DotsIndicator初始化报错dotsCount must be superior to zero

在Flutter项目中发送HTTP请求并展示数据时,出现如下错误:

dotsCount must be superior to zero
'package:dots_indicator/src/dots_indicator.dart':
Failed assertion: line 31 pos 16: 'dotsCount > 0'

初始状态下_free_items为空列表,HTTP请求完成加载数据后应用会恢复正常运行;但将DotsIndicator的dotsCount设置为固定数值(如10)时,该错误不会发生。相关代码如下:

import 'dart:convert';
import 'package:requests/home_page_free.dart';
import 'package:dots_indicator/dots_indicator.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
import '../../widgets/small_text.dart';

class HomePageBody extends StatefulWidget {
  const HomePageBody({super.key});

  @override
  State<HomePageBody> createState() => _HomePageBodyState();
}

class _HomePageBodyState extends State<HomePageBody> {
  PageController freeController = PageController(viewportFraction: 0.85);
  var _freeCurrentPageValue = 0.0;
  var _freeScaleFactor = 0.8;
  double _height = 320;

  List<MainFree> _free_items = [];
   
  @override
  void initState() {
    freeController.addListener(() {
      setState(() {
        _freeCurrentPageValue = freeController.page!;
      });
    });
    freeItem();
    super.initState();
  }

  @override
  void dispose() {
    freeController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: SingleChildScrollView(
        child: Column(
            children: [
              Container(
              height: MediaQuery.of(context).size.height/3.6,
              child: PageView.builder(
                  controller: freeController,
                  itemCount: _free_items.length,
                  itemBuilder: (context, position){
                    return _freePageItem(position, _free_items[position]);
                  }
                  ),
              ),
              new DotsIndicator(
                dotsCount: _free_items.length,
                position: _freeCurrentPageValue ,
                decorator: DotsDecorator(
                  size: const Size.square(9.0),
                  activeSize: const Size(18.0, 9.0),
                  activeShape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5.0)),
                ),
              ),
            ]
        ),
      ),
    );
  }

  Widget _freePageItem(int index, MainFree free){
    return Stack(
      children: [
        Container(
          height: MediaQuery.of(context).size.height/6,
          margin: EdgeInsets.only(left: 5, right: 5),
          decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(30),
              color: Colors.deepOrange,
              image: DecorationImage(
                  fit: BoxFit.cover,
                  image: NetworkImage(
                      free.app_image
                  )
              )

          ),
        ),
        Align(
          alignment: Alignment.bottomCenter,
          child: Container(
            height: 110,
            margin: EdgeInsets.only(left: MediaQuery.of(context).size.width/20,
                right: MediaQuery.of(context).size.width/20,
                bottom: MediaQuery.of(context).size.height/28),
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(MediaQuery.of(context).size.height/28),
              color: Colors.white,
              boxShadow: [
                BoxShadow(
                  color: Color(0xFFe8e8e8),
                  blurRadius: 5.0,
                  offset: Offset(5, 5),
                ),
                BoxShadow(
                  color: Colors.white,
                  offset: Offset(-5, 0),
                ),
                BoxShadow(
                  color: Colors.white,
                  offset: Offset(5, 0),
                ),
              ],
            ),
            child: Container(
              padding: EdgeInsets.only(
                  top: 10, right: 15, left: 15
              ),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text('title of data', style: TextStyle(fontSize: 15),),
                  SizedBox(height: MediaQuery.of(context).size.height/120,),
                  Text('des of data', style: TextStyle(fontSize: 12, color: Colors.black54),),
                  SizedBox(height: MediaQuery.of(context).size.height/130,),
                  Row(
                    children: [
                      Wrap(children: List.generate((5), (index) => Icon(Icons.star,))),
                      Row(
                        children: [
                          SizedBox(width: 10),
                          SmallText(text: "4.5"),
                          SizedBox(width: 10),
                          SmallText(text: "1287"),
                          SizedBox(width: 10),
                          SmallText(text: "comments"),
                        ],
                      ),
                    ],
                  ),
                  SizedBox(height: MediaQuery.of(context).size.height/130,),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      Container(
                        child: Row(
                          children: [
                            Icon(Icons.lock_clock, color: Colors.orange,),
                            SizedBox(width: 5,),
                            SmallText(text: 'text')
                          ],
                        ),
                      ),
                      Container(
                        child: Row(
                          children: [
                            Icon(Icons.military_tech, color: Colors.tealAccent),
                            SizedBox(width: 5,),
                            SmallText(text: 'text')
                          ],
                        ),
                      ),
                      Container(
                        child: Row(
                          children: [
                            Icon(Icons.time_to_leave, color: Colors.pink),
                            SizedBox(width: 5,),
                            SmallText(text: 'text')
                          ],
                        ),
                      ),
                    ],
                  )
                ],
              ),
            ),
          ),
        ),
      ],
    );
  }
  void freeItem() async{
    var url = Uri.https('www.geors.ir', '/api_free/', {'q': '{http}'});
    var response = await get(url);
    setState(() {
      var free_json = json.decode(utf8.decode(response.bodyBytes));
      for (var i in free_json){
        var free_items = MainFree(i['title'], i['app_image'], i['category'], i['tech_count'],  

        i['views'], i['meta_description']);
        _free_items.add(free_items);
      }
    });
  }
}

修复方案

方案一:给dotsCount设置最小默认值

因为初始时_free_items.length为0,直接传给dotsCount会触发断言失败。可以通过三元运算符设置最小为1:

DotsIndicator(
  dotsCount: _free_items.length > 0 ? _free_items.length : 1,
  position: _freeCurrentPageValue ,
  decorator: DotsDecorator(
    size: const Size.square(9.0),
    activeSize: const Size(18.0, 9.0),
    activeShape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5.0)),
  ),
),

初始时会显示1个占位点,数据加载完成后自动切换为实际数量的点。

方案二:条件渲染DotsIndicator

当_free_items为空时,不渲染DotsIndicator,或者显示加载提示:

// 替换原DotsIndicator代码
_free_items.isEmpty 
    ? SizedBox.shrink() // 或替换为CircularProgressIndicator()显示加载状态
    : DotsIndicator(
        dotsCount: _free_items.length,
        position: _freeCurrentPageValue,
        decorator: DotsDecorator(
          size: const Size.square(9.0),
          activeSize: const Size(18.0, 9.0),
          activeShape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5.0)),
        ),
      ),

这种方式更严谨,只有数据加载完成后才显示指示器。

额外优化:给PageView添加空状态处理

PageView在_free_items为空时没有内容,建议同时处理:

// 替换原PageView.builder代码
_free_items.isEmpty
    ? Center(child: CircularProgressIndicator()) // 显示加载中提示
    : PageView.builder(
        controller: freeController,
        itemCount: _free_items.length,
        itemBuilder: (context, position){
          return _freePageItem(position, _free_items[position]);
        },
      ),

用户等待数据加载时能看到加载状态,体验更友好。

内容的提问来源于stack exchange,提问作者jabar majidi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 01:55:03