macOS SwiftUI:解决Toggle窗口失活变色,替代tintAdjustmentMode功能
解决方案
方案1:强制Toggle保持原有tint颜色不变
系统默认的switch样式会在窗口失活时自动降低tint饱和度,要规避这个行为,需自定义ToggleStyle,完全接管开关绘制逻辑,不受系统自动调整影响:
struct FixedTintSwitchStyle: ToggleStyle { let tintColor: Color let canActivate: Bool func makeBody(configuration: Configuration) -> some View { HStack { Spacer() ZStack(alignment: configuration.isOn ? .trailing : .leading) { // 开关背景 Capsule(style: .continuous) .fill(configuration.isOn ? tintColor.opacity(0.3) : Color(.systemGray5)) .frame(width: 51, height: 31) // 开关滑块 Circle() .fill(Color.white) .shadow(radius: 1) .padding(3) .frame(width: 25, height: 25) .offset(x: configuration.isOn ? 10 : -10) .animation(.easeInOut(duration: 0.2), value: configuration.isOn) } .onTapGesture { guard canActivate else { return } configuration.isOn.toggle() } .opacity(canActivate ? 1 : 0.5) Spacer() } .overlay( canActivate ? Capsule(style: .continuous).stroke(tintColor) : nil ) } } // 使用方式 Toggle(isOn: $userManagedIsActive) { EmptyView() } .disabled(!canActivate) .toggleStyle(FixedTintSwitchStyle(tintColor: toggleColor(), canActivate: canActivate))
该自定义样式完全脱离系统默认tint调整逻辑,无论窗口是否激活,都会使用你指定的tintColor,尺寸和交互逻辑与系统原生开关对齐。
方案2:让Overlay和Toggle同步变暗匹配系统风格
要让自定义overlay与系统Toggle的变暗效果同步,需监听窗口激活状态,动态调整颜色的饱和度/透明度,对齐系统行为:
struct SyncDimSwitchStyle: ToggleStyle { @State private var isWindowActive = true let tintColor: Color let canActivate: Bool func makeBody(configuration: Configuration) -> some View { Toggle(isOn: configuration.$isOn) { EmptyView() } .disabled(!canActivate) .toggleStyle(.switch) .tint(adjustedTintColor()) .overlay( canActivate ? Capsule(style: .continuous).stroke(adjustedTintColor()) : nil ) .onReceive(NotificationCenter.default.publisher(for: NSWindow.didBecomeMainNotification)) { _ in isWindowActive = true } .onReceive(NotificationCenter.default.publisher(for: NSWindow.didResignMainNotification)) { _ in isWindowActive = false } } private func adjustedTintColor() -> Color { guard canActivate else { return tintColor.opacity(0.5) } // 窗口失活时降低颜色饱和度和透明度,匹配系统默认效果 return isWindowActive ? tintColor : tintColor .saturation(0.3) .opacity(0.7) } } // 使用方式 Toggle(isOn: $userManagedIsActive) { EmptyView() } .toggleStyle(SyncDimSwitchStyle(tintColor: toggleColor(), canActivate: canActivate))
通过监听NSWindow的激活通知,动态调整颜色参数,让overlay的描边颜色与系统Toggle的变暗效果完全同步。可根据视觉需求微调saturation和opacity数值,匹配系统风格。
内容的提问来源于stack exchange,提问作者Peter Lapisu
相关产品推荐
相关产品推荐

