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

tvOS SwiftUI LazyVGrid 项的ContextMenu显示异常问题

问题修复方案

问题根源

  1. 自定义PrimitiveButtonStyle中手动维护@State private var isFocused并手动调用focusable,干扰了tvOS系统对焦点的管理,导致ContextMenu无法关联正确的网格项。
  2. List嵌套ScrollView的结构造成布局层级混乱,使得ContextMenu的定位计算出错,弹出到网格区域外。
  3. 用onTapGesture代替系统按钮的原生触发逻辑,破坏了ContextMenu的触发机制。

修复步骤

  1. 简化布局层级:移除外层的List和ScrollView,直接将LazyVGrid放在NavigationStack内,避免嵌套滚动容器的冲突。
  2. 修正焦点处理:删除自定义按钮样式中手动的focusable调用和@State isFocused,直接使用@Environment(\.isFocused)来控制样式,依赖系统的焦点管理。
  3. 恢复原生按钮逻辑:移除onTapGesture,让PrimitiveButtonStyle通过原生交互逻辑处理点击与长按触发。

修改后的完整代码

struct HomeView: View {
    var test : [String] = ["Item 1", "Item 2", "Item 3", "Item 4", "Item 5", "Item 6", "Item 7", "Item 8", "Item 9", "Item 10", "Item 11", "Item 12", "Item 13", "Item 14"]
    
    var body: some View {
        NavigationStack() {
            LazyVGrid(columns: Array(repeating: GridItem(.flexible()), count: 5), alignment: .leading, spacing: 80) {
                ForEach(test, id: \.self) { item in
                    Button(item) {
                        
                    }
                    .buttonStyle(MyButtonStyle())
                    .contextMenu {
                        Text("Context Menu for : \(item)")
                        Button("Add Favorite") {}
                    }
                }
            }
            .padding(.all, 30)
            .navigationTitle("Test")
        }
    }
}

struct MyButtonStyle: PrimitiveButtonStyle {
    @Environment(\.isFocused) var focused: Bool
    
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .compositingGroup()
            .frame(minWidth: 250, maxWidth: 250, minHeight: 125, maxHeight: 125)
            .padding([.all], 10)
            .multilineTextAlignment(.center)
            .background(RoundedRectangle(cornerRadius: 20).fill(focused ? .blue : .gray).opacity(0.7))
            .foregroundColor(.white)
            .onLongPressGesture {
                configuration.trigger()
            }
    }
}

额外说明

  • tvOS上的ContextMenu默认通过长按触发,修改后的代码保留了这一原生交互逻辑。
  • 用Array(repeating: GridItem(.flexible()), count: 5)简化了列的定义,效果和原代码一致。
  • 移除List后,用navigationTitle替代原Section的标题,保持界面逻辑清晰。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 04:35:25