带有很多按钮的 VStack 上的 DragGesture,如何检测拖动何时在按钮内

ina*_*own 2 ios swiftui

在 UIKit 中,这可以用这样的代码来完成:

if button.frame.contains(sender.location(in: rightStackView)) { ... }
Run Code Online (Sandbox Code Playgroud)

但是在 SwiftUI 中,我似乎找不到与 类似的任何内容frame.contains,那么我怎样才能找出拖动是在特定按钮或其他视图内的时间呢?

Asp*_*eri 5

好吧,代码有点多,所以我尽可能地简化它只是为了演示可能的方法(无框架重叠,拖动重定位,浮动拖动项目等)。此外,从问题中不清楚它将使用什么。无论如何,希望这个演示会以某种方式有用。

注意:使用 Xcode 11.2

这是结果

SwiftUI 拖动目标帧检测

这是一个带有预览提供程序的模块演示代码

import SwiftUI

struct DestinationDataKey: PreferenceKey {
    typealias Value = [DestinationData]

    static var defaultValue: [DestinationData] = []

    static func reduce(value: inout [DestinationData], nextValue: () -> [DestinationData]) {
        value.append(contentsOf: nextValue())
    }
}

struct DestinationData: Equatable {
    let destination: Int
    let frame: CGRect
}

struct DestinationDataSetter: View {
    let destination: Int

    var body: some View {
        GeometryReader { geometry in
            Rectangle()
                .fill(Color.clear)
                .preference(key: DestinationDataKey.self,
                            value: [DestinationData(destination: self.destination, frame: geometry.frame(in: .global))])
        }
    }
}

struct DestinationView: View {
    @Binding var active: Int
    let label: String
    let id: Int

    var body: some View {
        Button(action: {}, label: {
            Text(label).padding(10).background(self.active == id ? Color.red : Color.green)
        })
        .background(DestinationDataSetter(destination: id))
    }
}

struct TestDragging: View {
    @State var active = 0
    @State var destinations: [Int: CGRect] = [:]

    var body: some View {
        VStack {
            Text("Drag From Here").padding().background(Color.yellow)
                .gesture(DragGesture(minimumDistance: 0.1, coordinateSpace: .global)
                    .onChanged { value in
                        self.active = 0
                        for (id, frame) in self.destinations {
                            if frame.contains(value.location) {
                                self.active = id
                            }
                        }
                    }
                    .onEnded { value in
                        // do something on drop
                        self.active = 0
                    }
            )
            Divider()
            DestinationView(active: $active, label: "Drag Over Me", id: 1)
        }.onPreferenceChange(DestinationDataKey.self) { preferences in
            for p in preferences {
                self.destinations[p.destination] = p.frame
            }
        }
    }
}

struct TestDragging_Previews: PreviewProvider {
    static var previews: some View {
        TestDragging()
    }
}
Run Code Online (Sandbox Code Playgroud)