You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 06:44:53