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
相关产品推荐
相关产品推荐

