SwiftUI:如何基于列表选中状态动态更改自定义文本颜色?
解决SwiftUI macOS可选中列表行自定义颜色同步切换问题
在macOS的SwiftUI可选中列表中,通过selection绑定判断行选中状态会导致文本颜色切换延迟——背景在鼠标按下时就变色,但文本要到松开才更新。以下是两种纯SwiftUI的解决方法,能让文本颜色和背景同步变化:
方法一:跟踪鼠标按压状态
通过onTapGesture的pressing参数实时获取行的按压状态,结合选中状态一起判断文本颜色,消除延迟:
struct Item: Identifiable, Hashable { var id = UUID() var title: String } struct ContentView: View { @State var listContent = [Item(title: "A"), Item(title: "B"), Item(title: "C")] @State var selection: Item? @State private var pressedItem: Item? // 跟踪当前按压的行 var body: some View { List(selection: $selection) { ForEach(listContent, id: \.self) { item in HStack { Text(item.title) .foregroundStyle(.primary) // 系统自动处理选中变色 Text(item.title) .foregroundStyle(isItemActive(item) ? .white : .red) // 自定义颜色同步切换 } .onTapGesture(pressing: { isPressing in // 按压时记录当前行,松开时清空 pressedItem = isPressing ? item : nil }) {} } } } // 判断行是否处于选中或按压状态 private func isItemActive(_ item: Item) -> Bool { selection == item || pressedItem == item } }
方法二:利用环境变量检测高亮状态
通过自定义PreferenceKey捕获行的高亮状态(macOS原生列表行的高亮会在鼠标按下时触发),实现更贴合系统行为的颜色切换:
// 自定义PreferenceKey传递高亮状态 struct HighlightedPreferenceKey: PreferenceKey { static var defaultValue: Bool = false static func reduce(value: inout Bool, nextValue: () -> Bool) { value = value || nextValue() } } extension View { func onHighlighted(_ action: @escaping (Bool) -> Void) -> some View { self.background( GeometryReader { proxy in Color.clear.preference( key: HighlightedPreferenceKey.self, value: proxy.frame(in: .global).intersects(NSEvent.mouseLocation) && NSEvent.pressedMouseButtons > 0 ) } ) .onPreferenceChange(HighlightedPreferenceKey.self) { isHighlighted in action(isHighlighted) } } } struct ContentView: View { @State var listContent = [Item(title: "A"), Item(title: "B"), Item(title: "C")] @State var selection: Item? @State private var isItemHighlighted = false var body: some View { List(selection: $selection) { ForEach(listContent, id: \.self) { item in HStack { Text(item.title) .foregroundStyle(.primary) Text(item.title) .foregroundStyle(isItemActive(item) ? .white : .red) } .onHighlighted { isHighlighted in self.isItemHighlighted = isHighlighted } } } } private func isItemActive(_ item: Item) -> Bool { selection == item || isItemHighlighted } }
第一种方法更简洁,完全依赖SwiftUI的手势API,能完美解决延迟问题;第二种方法更贴近系统原生的高亮逻辑,适合需要更精细控制的场景。
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

