tvOS SwiftUI LazyVGrid 项的ContextMenu显示异常问题
问题修复方案
问题根源
- 自定义
PrimitiveButtonStyle中手动维护@State private var isFocused并手动调用focusable,干扰了tvOS系统对焦点的管理,导致ContextMenu无法关联正确的网格项。 List嵌套ScrollView的结构造成布局层级混乱,使得ContextMenu的定位计算出错,弹出到网格区域外。- 用
onTapGesture代替系统按钮的原生触发逻辑,破坏了ContextMenu的触发机制。
修复步骤
- 简化布局层级:移除外层的
List和ScrollView,直接将LazyVGrid放在NavigationStack内,避免嵌套滚动容器的冲突。 - 修正焦点处理:删除自定义按钮样式中手动的
focusable调用和@State isFocused,直接使用@Environment(\.isFocused)来控制样式,依赖系统的焦点管理。 - 恢复原生按钮逻辑:移除
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
相关产品推荐
相关产品推荐

