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

非原生可聚焦视图使用.focusable()失效问题求助

问题:SwiftUI中Text视图无法通过.focusable()和@FocusState正常获取焦点?

我在一个全新的跨平台SwiftUI项目中测试自定义视图的聚焦功能,先用Text视图做试验,但没能成功。.focusable()的核心功能不就是声明任意视图为可聚焦状态吗?如果是这样,为什么下面的代码无法正常工作?

import SwiftUI

struct ContentView: View {
    @FocusState private var focusedItem: Optional<FocusedItem>

    var body: some View {
        VStack {
            Text("Test")
                .focusable(true)
                .focused($focusedItem, equals: .two)

            Button("Toggle Focus") {
                self.focusedItem=(self.focusedItem == nil) ? .two : nil
                DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
                      
                    // 始终打印 `nil`
                    print(self.focusedItem)
                }
            }
        }
    }
    
    enum FocusedItem {
        case one, two
        func other() -> FocusedItem {
            switch self {
            case .one: return .two
            case .two: return .one
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

解决方案

问题根源在于Text是静态非交互视图,即使添加了.focusable(true),SwiftUI的焦点系统也不会主动为它维持焦点状态——尤其是在iOS这类以触摸交互为主的平台,静态文本默认不属于可焦点控件范畴;在macOS、tvOS等支持键盘焦点导航的平台,也需要视图具备交互能力才能被焦点系统正确识别。

修复步骤:

  • 给Text添加交互容器,比如用Button包裹并移除默认按钮样式,让视图具备交互响应能力
  • 可选添加焦点状态的视觉反馈,方便验证焦点是否生效

修改后的代码:

import SwiftUI

struct ContentView: View {
    @FocusState private var focusedItem: FocusedItem?

    var body: some View {
        VStack {
            // 用Button包裹Text,移除默认按钮样式,赋予交互能力
            Button(action: {}) {
                Text("Test")
            }
            .buttonStyle(.plain)
            .focusable(true)
            .focused($focusedItem, equals: .two)
            // 焦点状态的视觉反馈:聚焦时显示浅蓝色背景
            .background(focusedItem == .two ? Color.blue.opacity(0.2) : Color.clear)

            Button("Toggle Focus") {
                focusedItem = focusedItem == nil ? .two : nil
                DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
                    print(focusedItem) // 现在会正确输出.two或nil
                }
            }
        }
    }
    
    enum FocusedItem {
        case one, two
        func other() -> FocusedItem {
            switch self {
            case .one: return .two
            case .two: return .one
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

验证说明:

  • 在macOS上,点击Toggle Focus按钮后,3秒后控制台会正确打印.two;通过Tab键也能导航到该Text视图并触发焦点状态
  • 在iOS上,可通过辅助功能的「切换控制」或「VoiceOver」来测试焦点导航,此时Text视图会被识别为可焦点元素

内容的提问来源于stack exchange,提问作者shoe

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 23:45:43