macOS SwiftUI 应用全屏运行秒表时工具栏按钮闪烁问题求助
问题原因
你的工具栏闪烁是高频无意义视图重绘触发的macOS半透明工具栏渲染异常,根源来自以下两点:
- 你的
Stopwatch作为ObservableObject,其中@Published修饰的secondsElapsedString每0.1秒就会发布一次变更通知,所有监听这个Stopwatch实例的视图(包括你的主窗口根视图)都会触发完整重绘,工具栏也会跟着重绘 - macOS全屏状态下的半透明磨砂工具栏在高频重绘时会偶发材质渲染失败,表现为短时间闪白,和你遇到的现象完全吻合
验证方法
你可以临时把Timer的触发间隔从0.1秒改成1秒,会发现闪烁频率也同步变为1秒一次,即可确认问题来源。
修复方案
方案1:减少不必要的状态发布
在更新secondsElapsedString前先判断值是否真的发生了变化,避免无效发布触发重绘,同时把Timer加入Common运行模式避免UI事件打断调度,修改Timer的回调逻辑即可:
timer = Timer(timeInterval: 0.1, repeats: true) { [weak self] timer in guard let self = self, let startTime = self.startTime else { return } self.secondsElapsed = Date().timeIntervalSince(startTime) let newStr = String(format: "%.1f", self.secondsElapsed) // 仅当字符串变化时才更新@Published属性 guard newStr != self.secondsElapsedString else { return } self.secondsElapsedString = newStr } RunLoop.main.add(timer, forMode: .common) self.timer = timer
方案2:隔离状态监听范围
检查你Stopwatch实例的注入层级,如果是用@EnvironmentObject或者@StateObject挂在根视图/WindowGroup上,改为只在需要显示秒表数值的那一层子视图注入,从根源上避免工具栏监听秒表的状态变更。
方案3:固定工具栏视图避免重绘
给工具栏元素添加固定标识或Equatable修饰,让SwiftUI在全局刷新时判定工具栏无变化,跳过重绘:
.toolbar { ToolbarItemGroup() { Button(action: toggleSidebar, label: { Image(systemName: "sidebar.left") }) .help("Toggle the sidebar") .equatable() Button { showingAddInstanceSheet = true } label: { Image(systemName: "plus") } .help("Create new instance") .equatable() } .id("fixedToolbar") }
内容的提问来源于stack exchange,提问作者Cameron Delong
相关产品推荐
相关产品推荐

