1]相同的视图的许多实例被嵌入到一个数组中。主ContentView的子视图通过HStack中的ForEach显示它们。每个实例都有一个几何读取器,以检测拖动期间的框架相交。目标是在检测到相交时交换视图在主内容视图上的位置。使用下面的代码,它只是没有检测到交叉点。
是否有更好的方法(比array + foreach更好的方法来分组和显示某个视图的动态实例数?
var rects: [rect] = [rect(num:"0"),rect(num:"1"),rect(num:"2")]
struct rect: View {
let id = UUID()
let num: String
@State var viewFrame: CGRect = .zero
@State var viewOffset: CGSize = .zero
var body: some View {
Rectangle()
.stroke(Color.blue, lineWidth: 4)
.frame(width: 50, height: 100)
.offset(viewOffset)
.background(Text("\(num)"))
.overlay(GeometryReader { r in
Color.red
.opacity(0.5)
.onAppear {
self.viewFrame = r.frame(in: .global)
}
})
.gesture(DragGesture(minimumDistance: 0, coordinateSpace: .global)
.onChanged { value in
self.viewOffset = value.translation
}
.onEnded { value in
let newFrame = self.viewFrame.offsetBy(dx: self.viewOffset.width, dy: self.viewOffset.height)
if let swap_rect = rects.first(where: {$0.id != self.id && $0.viewFrame.intersects(newFrame)}) {
print("intersects")
rects.swapAt(rects.firstIndex(of: self), rects.firstIndex(of: swap_rect))
} else {
print("nope")
}
self.viewOffset = .zero
}
)
}
}
struct field: View {
var body: some View {
HStack {
ForEach(self.field_env.rects, id:\.id) { rect in
rect
}
}
}
}
struct ContentView: View {
var body: some View {
VStack {
field()
}
}
}
2]我能够做到这一点的唯一方法是通过将每个视图的其他GR冲突帧存储在environmentObject / ObservableObject的已发布数组var中。但是,一旦视图的两个实例交换了它们在主视图上的位置,似乎GR碰撞框架CGRects不会得到更新(因为GR仅具有onappear方法),并且下次我执行视图拖动和相交时,错误的视图将被交换(而不是视觉上相撞的)下面的代码显示3个标记为0,1,2的矩形(作为它们在数组中的索引)。第一次将“ 2”拖到“ 1”上时,它们可以正确交换,但是如果将“ 1”拖到“ 2”上,则“ 1”将被替换为“ 0”。```swift
class FieldEnv: ObservableObject {
@Published var rect_frames: [UUID:CGRect] = [:]
@Published var rects: [rect] = [rect(num:"0"),rect(num:"1"),rect(num:"2")]
}
struct rect: View {
@EnvironmentObject var field_env: FieldEnv
let id = UUID()
let num: String
@State var viewFrame: CGRect = .zero
@State var viewOffset: CGSize = .zero
var body: some View {
Rectangle()
.stroke(Color.blue, lineWidth: 4)
.frame(width: 50, height: 100)
.offset(viewOffset)
.background(Text("\(num)"))
.overlay(GeometryReader { r in
Color.red
.opacity(0.5)
.onAppear {
self.viewFrame = r.frame(in: .global)
self.field_env.rect_frames[self.id] = r.frame(in: .global)
}
})
.gesture(DragGesture(minimumDistance: 0, coordinateSpace: .global)
.onChanged { value in
self.viewOffset = value.translation
}
.onEnded { value in
let newFrame = self.viewFrame.offsetBy(dx: self.viewOffset.width, dy: self.viewOffset.height)
if let swap_rect = self.field_env.rect_frames.first(where: {$0.key != self.id && $0.value.intersects(newFrame)}) {
print("intersects")
withAnimation {
self.field_env.rects.swapAt(self.field_env.rects.firstIndex(of: self)!, self.field_env.rects.firstIndex(where: {$0.id == swap_rect.key})!)
}
} else {
print("nope")
}
self.viewOffset = .zero
}
)
}
}
struct field: View {
let NC = NotificationCenter.default
@EnvironmentObject var field_env: FieldEnv
var body: some View {
HStack {
ForEach(self.field_env.rects, id:\.id) { rect in
rect
}
}
}
}
struct ContentView: View {
var body: some View {
VStack {
field()
}
}
}
```
更新:
我尝试通过通知中心执行交换后手动更新GR视图帧,因为我认为GR每次都使用初始帧位置(在.onAppear期间获取),并且交换后事情变得混乱,但这似乎是问题所在在其他地方-仍然交换了错误的数组索引(而不是属于相交视图的数组索引):
```swift
struct rect: View {
@EnvironmentObject var field_env: FieldEnv
let NC = NotificationCenter.default
let id = UUID()
let num: String
@State var viewFrame: CGRect = .zero
@State var viewOffset: CGSize = .zero
var body: some View {
Rectangle()
.stroke(Color.blue, lineWidth: 4)
.frame(width: 50, height: 100)
.offset(viewOffset)
.background(Text("\(num)"))
.overlay(GeometryReader { r in
Color.red
.opacity(0.5)
.onAppear {
self.viewFrame = r.frame(in: .global)
self.field_env.rect_frames[self.id] = r.frame(in: .global)
self.NC.addObserver(forName: .cardsSwapped, object: nil, queue: nil, using: {_ in self.field_env.rect_frames[self.id] = r.frame(in: .global)})
}
})
.gesture(DragGesture(minimumDistance: 0, coordinateSpace: .global)
.onChanged { value in
self.viewOffset = value.translation
}
.onEnded { value in
let newFrame = self.viewFrame.offsetBy(dx: self.viewOffset.width, dy: self.viewOffset.height)
if let swap_rect = self.field_env.rect_frames.first(where: {$0.value.intersects(newFrame)}) {
print("intersects")
withAnimation {
self.field_env.rects.move(fromOffsets: [self.field_env.rects.firstIndex(of: self)!], toOffset: self.field_env.rects.firstIndex(where: {$0.id == swap_rect.key})!)
}
} else {
print("nope")
}
self.viewOffset = .zero
self.NC.post(name: .cardsSwapped, object: nil)
}
)
}
}
```
1]相同的视图的许多实例被嵌入到一个数组中。主ContentView的子视图通过HStack中的ForEach显示它们。每个实例都有一个几何读取器以检测框架...
strings