SwiftUI macOS List实现鼠标点击位置弹出Popover
在macOS SwiftUI List中实现Popover从鼠标精确点击位置弹出
要让Popover从List行的精确点击位置弹出,需捕获点击坐标并将其设为Popover的附着锚点,以下是修改后的完整实现:
核心修改点
- 捕获鼠标点击的精确坐标
- 获取List行的实际尺寸,将绝对坐标转换为相对单位点
- 用转换后的单位点作为Popover的附着锚点
完整代码
import SwiftUI struct TestPopoverView: View { let items = ["Row 1", "Row 2", "Row 3", "Row 4", "Row 5"] var body: some View { List(items, id: \.self) { item in ListRowView(item: item) } } } struct ListRowView: View { let item: String @State private var showPopover = false @State private var tapLocation: CGPoint = .zero @State private var rowSize: CGSize = .zero var body: some View { HStack { Text(item) .padding() Spacer() } // 获取当前行的尺寸 .background( GeometryReader { proxy in Color.clear .onAppear { rowSize = proxy.size } } ) .contentShape(Rectangle()) // 确保整行可点击 .onTapGesture { location in tapLocation = location showPopover = true } .popover( isPresented: $showPopover, // 将点击坐标转换为相对单位点作为锚点 attachmentAnchor: .point(UnitPoint( x: tapLocation.x / rowSize.width, y: tapLocation.y / rowSize.height )), arrowEdge: .bottom ) { PopoverContentView(item: item) } } } struct PopoverContentView: View { let item: String var body: some View { VStack { Text("Selected: \(item)") .padding() } .frame(width: 200, height: 100) } } #Preview { TestPopoverView() .frame(width: 300, height: 350) }
关键说明
- 视图尺寸获取:通过
GeometryReader包裹行背景,获取行的实际宽高,为坐标转换提供基准 - 点击坐标捕获:
onTapGesture的location参数直接返回鼠标点击的绝对坐标,存储到状态变量中 - 锚点转换:将绝对坐标除以行的宽高,得到0-1范围内的相对单位点,作为Popover的
attachmentAnchor,确保箭头精准指向点击位置 - 整行可点击:
contentShape(Rectangle())保留了原有的整行点击范围,不影响用户交互体验
内容的提问来源于stack exchange,提问作者Z S
相关产品推荐
相关产品推荐

