macOS中ScrollView内LazyVGrid按钮点击异常问题求助
macOS SwiftUI ScrollView嵌套LazyVGrid的按钮点击与Popover问题解决
问题根源
在双方向滚动的ScrollView内使用LazyVGrid时,窗口尺寸调整会触发布局重绘,SwiftUI的视图复用机制和坐标计算可能出现不同步,导致按钮点击区域失效、Popover锚点偏移或不显示。
解决方案
1. 采用popover(item:)替代isPresented绑定
将Popover的显示状态直接绑定到选中的Cell实例,避免布尔状态可能出现的不同步问题,同时确保Popover始终关联正确的单元格。
2. 明确按钮点击区域
给按钮设置与GridItem匹配的固定尺寸,避免因文本大小导致点击区域不稳定。
修改后的完整代码
import SwiftUI struct Cell: Identifiable { var id: UUID = UUID() var i: Int = 0 init(i: Int) { self.i = i } } struct ContentView: View { var columns: [GridItem] = [GridItem](repeating: GridItem(.fixed(40), spacing: 5), count: 60) var cells: [Cell] = [] @State private var selectedCell: Cell? init() { cells.removeAll() for i in 0..<180 { cells.append(Cell(i:i)) } } var body: some View { ScrollView([.horizontal, .vertical]) { LazyVGrid(columns: columns, spacing: 5) { ForEach(cells) { cell in ButtonView(cell: cell, selectedCell: $selectedCell) } } } } } struct ButtonView: View { var cell: Cell @Binding var selectedCell: Cell? var body: some View { Button { selectedCell = cell } label: { Text("\(cell.i)") .frame(width: 40, height: 40) .background(Color.gray.opacity(0.1)) // 可选,便于可视化点击区域 } .buttonStyle(.plain) .popover(item: $selectedCell) { selectedCell in Text("Information line of button \(selectedCell.i)").padding() } } } #Preview { ContentView() }
额外优化(可选)
如果仍存在坐标偏移问题,可以监听窗口 resize 事件,手动更新视图坐标:
在ButtonView中添加GeometryReader获取按钮全局坐标,并指定Popover的锚点:
struct ButtonView: View { var cell: Cell @Binding var selectedCell: Cell? @State private var buttonFrame: CGRect = .zero var body: some View { Button { selectedCell = cell } label: { Text("\(cell.i)") .frame(width: 40, height: 40) .background(Color.gray.opacity(0.1)) } .background( GeometryReader { geo in Color.clear .onAppear { buttonFrame = geo.frame(in: .global) } .onReceive(NotificationCenter.default.publisher(for: NSWindow.didResizeNotification)) { _ in buttonFrame = geo.frame(in: .global) } } ) .buttonStyle(.plain) .popover(item: $selectedCell, attachmentAnchor: .rect(.bounds), source: buttonFrame) { selectedCell in Text("Information line of button \(selectedCell.i)").padding() } } }
内容的提问来源于stack exchange,提问作者George Papadopoulos
相关产品推荐
相关产品推荐

