如何检测DraggableScrollableSheet下拉状态?setState下extent判断失效
问题原因
- 浮点数精度误差:拖拽回调返回的
extent是实时计算的双精度浮点值,控制台打印显示为0.49是输出时做了长度截断,实际值通常是0.489999999997、0.490000000002这类接近值,直接用== 0.49判断几乎不可能命中。 - 判断逻辑存在覆盖:两个独立的if判断没有互斥关系,就算extent真的等于0.49,第一个分支将
scrolable设为true后,会立刻命中第二个extent <= 0.49的分支,把值改回false,这就是注释setState后变量也始终为false的直接原因。 - 无差别setState导致重建异常:如果在每帧的拖拽回调里都调用setState,会高频触发组件树重建,打断拖拽手势的事件流转,反而导致extent计算出错、判断逻辑不生效。
可直接运行的修复代码
NotificationListener<DraggableScrollableNotification>( onNotification: (DraggableScrollableNotification DSNotification) { // 增加精度容差判断是否到达最大展开位,避免浮点数精度问题 bool isReachMax = (DSNotification.maxExtent - DSNotification.extent).abs() < 0.001; bool newScrollableState = isReachMax; // 仅当状态实际变化时才触发更新,避免每帧重建干扰拖拽逻辑 if (newScrollableState != scrolable) { setState(() { scrolable = newScrollableState; }); } print(scrolable); return true; }, child: DraggableScrollableSheet( controller: controller, initialChildSize: 0, minChildSize: 0.0, maxChildSize: 0.49, builder: (_, scrollController) { return Container( decoration: BoxDecoration( color: Colors.white, border: Border.all(color: Colors.transparent), borderRadius: const BorderRadius.only( topLeft: Radius.circular(15), topRight: Radius.circular(15))), child: ListView(controller: scrollController, children: [ nfController.myWidget, ]), ); }, ), )
修复点说明
- 浮点数判断保留0.001的精度容差,同时直接取回调自带的
maxExtent做对比,后续修改maxChildSize参数时不需要同步调整判断逻辑。 - 先计算最终要设置的状态值,仅当新值和当前存储值不一致时才调用setState,过滤掉大量无意义的高频重建。
- 移除了重复的独立判断分支,从逻辑上避免状态值被后续逻辑覆盖的问题。
内容的提问来源于stack exchange,提问作者Abmb
相关产品推荐
相关产品推荐

