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

SwiftUI:如何在onLongPressGesture中获取列表项CGRect并存储于列表视图?

解决方案

可以通过PreferenceKey实现,在父视图(ContentView)中统一存储所有列表项的CGRect,并在长按触发时获取对应项的坐标,具体实现如下:

1. 定义偏好键传递坐标数据

首先创建一个自定义PreferenceKey,用来携带每个列表项的ID和对应的全局坐标:

struct ItemFramePreferenceKey: PreferenceKey {
    static var defaultValue: [Int: CGRect] = [:]
    
    static func reduce(value: inout [Int: CGRect], nextValue: () -> [Int: CGRect]) {
        value.merge(nextValue()) { $1 }
    }
}

2. 修改ContentView实现逻辑

在原ContentView中添加状态变量存储所有项的坐标,通过GeometryReader捕获每个列表项的位置,并通过偏好键传递给父视图,最后在长按回调中根据ID获取对应坐标:

struct ContentView: View {
    // 存储每个列表项的ID和对应的CGRect
    @State private var itemFrames: [Int: CGRect] = [:]
    
    var body: some View {
        ScrollView {
            LazyVStack {
                ForEach((1...10), id: \.self) { itemId in
                    Text("\(itemId)")
                        .frame(height: 80)
                        .frame(maxWidth: .infinity)
                        .background(.yellow)
                        // 捕获当前视图的全局坐标,通过偏好键传递给父视图
                        .background(GeometryReader { geo in
                            Color.clear
                                .preference(
                                    key: ItemFramePreferenceKey.self,
                                    value: [itemId: geo.frame(in: .global)]
                                )
                        })
                        .onLongPressGesture {
                            // 根据当前item的ID取出对应的CGRect
                            if let rect = itemFrames[itemId] {
                                print("长按项\(itemId)的坐标:\(rect)")
                                // 在这里使用rect做后续操作
                            }
                        }
                }
            }
            // 监听偏好键变化,更新itemFrames
            .onPreferenceChange(ItemFramePreferenceKey.self) { newFrames in
                itemFrames = newFrames
            }
        }
    }
}

说明

  • PreferenceKey是SwiftUI中父子视图传递数据的常用方式,这里用来将每个列表项的坐标统一收集到父视图的itemFrames字典中。
  • GeometryReader的frame(in: .global)会返回视图在屏幕坐标系中的位置和大小,确保拿到的是全局坐标。
  • 由于使用了LazyVStack,列表项会按需加载,PreferenceKey的reduce方法会自动合并新出现的项的坐标,保证itemFrames始终是最新的。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 20:40:26