Flutter Slider报value超出min-max范围断言错误解决方案
问题报错说明
实现从数据库获取动态数据赋值给Slider组件value属性的功能时,先遇到值类型不匹配报错,将字符串格式的距离数据转换为double类型后,触发如下断言错误:Failed assertion: line 147 pos 15: 'value >= min && value <= max': is not true.
当前从数据库获取的distance字段值为17.00,存储在data[0]['distance']中,不清楚如何正确配置从数据库读取的min、max参数值,原有业务代码存在逻辑问题导致报错。
错误产生原因
- 变量初始化时序错误:读取接口数据给距离变量赋值的逻辑写在了类根成员位置,这部分代码会在组件初始化时立刻执行,远早于异步接口请求返回的时间,此时
data为null,不仅会触发空读取错误,后续接口返回新数据后,相关变量也不会自动同步更新。 - 数值量级不匹配:当前Slider配置的取值范围是0-100,但显示距离时使用了
(_vlaue * 100).round()的逻辑,说明原本设计的_vlaue是0-1之间的比例值,而数据库返回的17.00是实际英里数,直接赋值时17远大于比例值上限1,必然超出Slider取值范围触发断言。 - 无空值兜底:首次渲染组件时接口数据还未返回,没有给
_vlaue设置合法的初始默认值,传入非法空值也会触发范围校验失败。
可行修复方案
- 将Slider相关状态变量统一放到类成员中声明,给滑动值设置合法初始默认值,等接口返回数据后,再在
setState中更新距离值,禁止在类成员初始化位置直接读取未加载完成的异步数据。 - 统一数值量级:如果Slider的max设为100(对应100英里)、min设为1(和页面底部1英里的文案对齐),数据库返回的17.00就是直接的英里数,不需要额外乘100,直接赋值给滑动值即可;如果要保留0-1的比例逻辑,就将数据库返回的英里数除以100转成比例再赋值,同步保留显示文案的乘100逻辑。
- 增加加载态判断与值范围兜底:接口数据未返回前用默认值渲染Slider,对传入Slider的value值用
clamp(min, max)方法做强制范围限制,就算数据库返回超出区间的异常值,也不会触发范围断言错误。
修正后的可运行核心代码如下:
class Editprofile extends StatefulWidget { Editprofile({Key? key}) : super(key: key); @override _Editprofile createState() => _Editprofile(); } class _Editprofile extends State<Editprofile>{ var UsrID = Auth.prefs?.getString('usrid'); var data; // 初始化滑动值默认值,和Slider的min值保持一致 double _vlaue = 1; // 加载态标记,避免未拿到接口数据时渲染异常 bool _isLoading = true; @override void initState() { super.initState(); getData(); } getData() async{ var res = await http.get(Uri.https('www.*******.net', '/mm_api/index.php',{'act':'profile','UsrID': '${UsrID}'})); data = jsonDecode(res.body); // 接口返回后再解析距离值,做强制范围兜底 double dbDistance = double.parse('${data[0]['distance']}'); // clamp方法会自动将值限制在1-100区间内,彻底避免范围越界 _vlaue = dbDistance.clamp(1, 100); _isLoading = false; setState(() {}); } void _setvalue(double vlaue) => setState(() => _vlaue = vlaue); @override Widget build(BuildContext context){ // 加载中可显示加载指示器,也可直接用默认值渲染Slider if(_isLoading){ return Scaffold( body: Center(child: CircularProgressIndicator()), ); } return Scaffold( body: Container( padding: const EdgeInsets.all(16), child: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children:[ Text( 'Distance', style: TextStyle( color: Color(0xff2c3531), ), ), Directionality( textDirection: TextDirection.ltr, child: Text( // 统一量级:_vlaue本身就是英里数,无需乘100 '${_vlaue.round()} miles', style: TextStyle( color: Color(0xff2c3531), ), ), ), ] ), SizedBox( child: Slider( min: 1, // 和底部"1 Miles"文案对齐 max: 100, // 和底部"100 Miles"文案对齐 value: _vlaue, onChanged: _setvalue, inactiveColor: Color(0xff9a9a9a), activeColor: Color(0xff8f9df2), thumbColor: Color(0xff8f9df2), ), ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children:[ Text( '1 Miles', style: TextStyle( color: Color(0xff2c3531), ), ), Directionality( textDirection: TextDirection.ltr, child: Text( '100 Miles', style: TextStyle( color: Color(0xff2c3531), ), ), ), ] ), ], ), ) ); } }
核心避坑规则:所有依赖异步接口数据的组件属性,都不能在类成员初始化位置直接读取异步数据,必须等接口返回后在setState中更新。对传入Slider的value值做范围兜底,可以100%避免范围类断言错误。
内容的提问来源于stack exchange,提问作者RAF Algowid
相关产品推荐
相关产品推荐

