Release v1.2.0
本版本修复了悬浮按钮和检查器面板的根本性稳定性问题,并新增 FPS 监控演示。
This release fixes fundamental stability issues with the floating button and inspector panel, and adds FPS monitoring demos.
修复 / Bug Fixes:
- 修复悬浮按钮从未通过 Overlay 正常显示的问题
- Fixed issue where the floating button was never properly displayed via Overlay
- 根因:原实现使用
Overlay.of(context, rootOverlay: true)查找 Overlay,但Overlay是Navigator的子组件而非祖先,导致查找结果为null,按钮 OverlayEntry 从未被创建 - Root cause: Original implementation used
Overlay.of(context, rootOverlay: true)to find Overlay, but Overlay is a child of Navigator, not an ancestor, returningnulland the button OverlayEntry was never created - 修复:改用
navigatorState.overlay直接从 Navigator 获取其内部 Overlay,并加入下一帧重试机制应对 Navigator 未挂载的情况 - Fix: Use
navigatorState.overlayto get Overlay directly from Navigator, with next-frame retry when Navigator is not mounted
- 修复开启 FPS 监控后悬浮按钮消失、面板无法展开的问题
- Fixed issue where enabling FPS monitoring caused the floating button to disappear and the panel could not expand
- 根因:
FpsService.notifyListeners()会触发 Overlay 重建,叠加原 Overlay 查找失败,导致按钮 State 被销毁且无法恢复 - Root cause:
FpsService.notifyListeners()triggers Overlay rebuild; combined with the original Overlay lookup failure, the button State was destroyed and could not recover
- 修复 OverlayEntry 内容报 "No Material widget found" 的问题
- Fixed "No Material widget found" error in OverlayEntry content
- 面板 OverlayEntry 内部的
TabBar、IconButton、InkWell等 Material 组件因 OverlayEntry 不在 MaterialApp widget 树中而无法找到 Material 祖先 - Material widgets (TabBar, IconButton, InkWell) inside the panel OverlayEntry could not find a Material ancestor because OverlayEntry content is outside MaterialApp's widget tree
- 修复:在面板 OverlayEntry 内部(
Offstage内部)包裹Material(color: Colors.transparent)作为祖先 - Fix: Wrap
Material(color: Colors.transparent)insideOffstageto provide the Material ancestor
- 修复 OverlayEntry 的 Material 包裹导致下方页面无法点击/滑动的问题
- Fixed issue where Material wrapper in OverlayEntry made the underlying page unclickable/unscrollable
- 根因:
RenderMaterial只要设置了 color(即使Colors.transparent)就会在hitTestSelf返回true,拦截所有触摸事件 - Root cause:
RenderMaterialwith any color (evenColors.transparent) returnstrueinhitTestSelf, intercepting all touch events - 修复 1:按钮 OverlayEntry 不再包裹 Material(
FloatingInspectorButton内部无 InkWell/InkResponse,不需要 Material 祖先) - Fix 1: Button OverlayEntry no longer wraps Material (FloatingInspectorButton has no InkWell/InkResponse, no Material ancestor needed)
- 修复 2:面板 OverlayEntry 中将
Material放在Offstage内部,关闭面板时RenderOffstage.hitTest直接返回false,Material 不参与命中测试,点击穿透到下方页面 - Fix 2: In panel OverlayEntry,
Materialis placed insideOffstage; when the panel is closed,RenderOffstage.hitTestreturnsfalsedirectly, so Material never participates in hit testing and clicks pass through to the underlying page
- 修复 FPS Tab 切换后内容消失的问题
- Fixed issue where FPS Tab content disappeared after switching tabs
- 使用
IndexedStack替代TabBarView,并为每个 viewer 添加ValueKey确保状态保持 - Use
IndexedStackinstead ofTabBarView, and addValueKeyto each viewer to ensure state preservation
- 修复
AutomaticKeepAliveClientMixin与IndexedStack冲突导致状态销毁的问题- Fixed state destruction caused by conflict between
AutomaticKeepAliveClientMixinandIndexedStack - 移除所有 viewer(network/log/database/memory/fps/route)中的
AutomaticKeepAliveClientMixin - Remove
AutomaticKeepAliveClientMixinfrom all viewers (network/log/database/memory/fps/route)
- Fixed state destruction caused by conflict between
- 修复 FPS 计算严重偏低的问题(实际 60 FPS 仅显示 9-10)
- Fixed severely undercounted FPS (real 60 FPS showed only 9-10)
- 根因:
_onFrameTimings中_recentFrameTimestamps.add(now)在 for 循环外,而 Flutter 引擎的addTimingsCallback是批量回调,一次可能返回多帧,但代码每批只记录 1 个时间戳,导致 FPS 计算偏低 6-10 倍 - Root cause:
_recentFrameTimestamps.add(now)was outside the for-loop in_onFrameTimings; Flutter engine'saddTimingsCallbackis batched (may return multiple frames per call), but only one timestamp was added per batch, undercounting FPS by 6-10x - 修复:将
_recentFrameTimestamps.add移入 for 循环内,使用timing.timestamp.inMicroseconds为每帧单独记录时间戳 - Fix: Move
_recentFrameTimestamps.addinside the for-loop, usingtiming.timestamp.inMicrosecondsto record a timestamp per frame
新功能 / New Features:
- 悬浮按钮新增边缘吸附收入功能
- Floating button now auto-docks and tucks into screen edge
- 拖动松手后自动吸附到最近边缘,平滑动画"收入"边缘仅露出 24px 小弧边
- Auto-docks to nearest edge on release with smooth animation; tucks into edge leaving only a 24px peek
- 收入状态下点击露出部分会平滑拉出到完整可见位置(不打开面板,避免误触),再次点击才打开面板
- Tapping the peek smoothly pulls it out to fully visible (panel not opened, avoids accidental open); tap again to open the panel
- 此设计避免了从吸附态拖出时与系统返回手势(Android/iOS 边缘右滑退出)的冲突
- This design avoids conflict with system back gestures (Android/iOS edge swipe to go back) when pulling out from docked state
- 收入时图标变为方向箭头(左吸附→右箭头,右吸附→左箭头),提示可点击拉出
- Icon changes to directional chevron when tucked (left dock → right chevron, right dock → left chevron) hinting at tap-to-pull-out
- 非吸附状态保持虫子图标,点击直接打开面板
- Bug icon preserved when not docked; tap directly opens the panel
- Example App 新增 FPS 演示模块
- Example App adds FPS demo module
- Trigger Jank 按钮(阻塞主线程 100-500ms 模拟掉帧)
- Trigger Jank button (blocks main thread 100-500ms to simulate jank)
- Heavy Animations 演示(80 个同时旋转+缩放的 widget 故意触发掉帧)
- Heavy Animations demo (80 simultaneously rotating+scaling widgets to intentionally trigger jank)
- Smooth Animation 演示(单个轻量复合动画,演示稳定 60 FPS)
- Smooth Animation demo (single lightweight compound animation, demonstrates stable 60 FPS)