在UIKit中,可以使用以下代码完成此操作:
if button.frame.contains(sender.location(in: rightStackView)) { ... }
但是在SwiftUI中,我似乎找不到与frame.contains
类似的东西,
那么如何确定拖动在特定按钮或其他视图中的时间?
答案 0 :(得分:1)
好吧,这是很多代码,所以我尽可能地简化了它,以演示可能的方法(不包括帧重叠,拖动重定位,浮动拖动项等)。此外,从问题上不清楚将使用什么。无论如何,希望该演示会有所帮助。
注意:使用过Xcode 11.2
这是结果
这是预览提供程序的一个模块演示代码
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()
}
}
答案 1 :(得分:1)
这似乎与您想要实现的目标非常接近:
这来自here
(对不起,这个答案没有适应你的具体情况。我刚刚在做类似的事情,想分享一下)
struct ContentView: View {
@State private var frames = [CGRect]()
@State private var states = [false, false, false]
let values = ["First", "Second", "Third"]
var body: some View {
// This came from https://www.youtube.com/watch?v=ffV_fYcFoX0&t=6175s
HStack {
ForEach(0 ..< values.count) { index in
Text(values[index])
.overlay(
// Creating an overlay creates a view that matches the size of the original view
GeometryReader { geo in
Color.clear
.onAppear {
// Insert that into a state array, and now can access the coordinates of frames
frames.insert((geo.frame(in: .global)), at: 0)
}
}
)
}
.gesture(
DragGesture(minimumDistance: 0, coordinateSpace: .global)
.onChanged { value in
// If there's a match activate the view by toggling state
if let match = frames.firstIndex(where: { $0.contains(value.location) }) {
states[match] = true
}
}
.onEnded { _ in
}
)
}
}
}