View SwiftUI:如何检测两个视图是否相交?

View SwiftUI:如何检测两个视图是否相交?,view,swiftui,frame,intersection,View,Swiftui,Frame,Intersection,一个视图与另一个视图相交。我们如何在SwiftUI中检测这个十字路口 在Swift中,我将通过几行代码实现这一点: import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let a = UIView(frame: CGRect(x: 100, y: 100, width: 150, height: 150)) a.

一个视图与另一个视图相交。我们如何在SwiftUI中检测这个十字路口

在Swift中,我将通过几行代码实现这一点:

import UIKit

class ViewController: UIViewController {

override func viewDidLoad() {
    super.viewDidLoad()

    let a = UIView(frame: CGRect(x: 100, y: 100, width: 150, height: 150))
    a.backgroundColor = .purple
    view.addSubview(a)

    let b = UIView(frame: CGRect(x: 150, y: 150, width: 150, height: 150))
    b.backgroundColor = .orange
    view.addSubview(b)

    if a.frame.intersects(b.frame) {
        print("yes!")
    } else {
        print("no intersection!")
    }

  }

}
显然,它与SwiftUI无关:我们这里有另一个框架概念。什么可以替代?有人有主意吗

更新:

非常感谢他们的帮助和建议! 以下是我尝试使用矩形数组解决问题的方法:

import SwiftUI

struct ContentView: View {

@State var rect = CGRect()
@State var aRects = [CGRect]()


var body: some View {

    VStack {
        ZStack {
            Rectangle()
                  .frame(width: 150, height: 300)
                  .foregroundColor(.purple)
                  .background(self.rectReader(self.$rect))
                  HStack {
                      Spacer()
                      Spacer()
                      Spacer()
                      Rectangle()
                          .frame(width: 150, height: 180)
                          .foregroundColor(.pink)
                         .background(self.rectReader(self.$rect))
                      Spacer()
                  }
            }

        Button(action: {
             //print("aRects: \(self.aRects)")
             self.checkIntersection()
         }){
            Text("Check Intersection!")
         }
    }



}


// fill array of rects here
func rectReader(_ binding: Binding<CGRect>) -> some View {
    return GeometryReader { (geometry) -> AnyView in
        let rect = geometry.frame(in: .global)
        DispatchQueue.main.async {
            binding.wrappedValue = rect
            print("rect: \(self.rect)")
            self.aRects.append(self.rect)
        }
        return AnyView(Rectangle().fill(Color.clear))
    }
}

func checkIntersection() {
    if aRects.count == 2 {
        if self.aRects[0].intersects(self.aRects[1]) {
            print("yes!")
        } else {
            print("no!")
        }
    }
}

}

struct ContentView_Previews: PreviewProvider {
static var previews: some View {
    ContentView()
}
}
导入快捷界面
结构ContentView:View{
@状态变量rect=CGRect()
@状态变量aRects=[CGRect]()
var body:一些观点{
VStack{
ZStack{
矩形()
.框架(宽度:150,高度:300)
.foregroundColor(.紫色)
.background(self.rectReader(self.$rect))
HStack{
垫片()
垫片()
垫片()
矩形()
.框架(宽度:150,高度:180)
.foregroundColor(.粉色)
.background(self.rectReader(self.$rect))
垫片()
}
}
按钮(操作:{
//打印(“aRects:\(self.aRects)”)
self.checkIntersection()
}){
文本(“检查交点!”)
}
}
}
//在这里填充矩形数组
func rectReader(u-binding:binding)->一些视图{
返回GeometryReader{(几何)->中的任意视图
设rect=geometry.frame(in:.全局)
DispatchQueue.main.async{
binding.wrappedValue=rect
打印(“rect:\(self.rect)”)
self.aRects.append(self.rect)
}
返回任意视图(矩形().fill(Color.clear))
}
}
func checkIntersection(){
如果aRects.count==2{
如果self.aRects[0]相交(self.aRects[1]){
打印(“是!”)
}否则{
打印(“否!”)
}
}
}
}
结构内容视图\u预览:PreviewProvider{
静态var预览:一些视图{
ContentView()
}
}

你的问题一点也不愚蠢

这似乎很容易

  • 读取第一个视图的框架(在全局坐标中)并将其保存在首选项中
  • 读取第二个视图的框架(在全局坐标中)并将其保存在首选项中
  • 更改首选项时计算交点
  • 创建我们的首选项键结构很容易,之前已经在这个网站上解释过(使用搜索获得更多详细信息:-))

    已经解释了在背景视图修改器中使用GeometryReader

    struct SizeReader: View {
        var body: some View {
            GeometryReader { proxy in
                Color.clear
                .preference(key: Sizes.self, value: [proxy.frame(in: .global)])
            }
        }
    }
    
    现在,我们可以使用它来保存我们的尺寸偏好键中的帧矩形

    RectView(color: .pink).background(SizeReader())
    
    那我们的观点呢?为了演示我们的“简单解决方案”是如何工作的,想象一下有人用随机大小和随机对齐创建它

    struct RectView: View {
        let color: Color
        let size = CGFloat(Int.random(in: 50 ... 200))
        var body: some View {
            color.frame(width: size, height: size)
                .alignmentGuide(HorizontalAlignment.center) {
                    CGFloat.random(in: 0 ..< $0.width)
                }
                .alignmentGuide(VerticalAlignment.center) {
                    CGFloat.random(in: 0 ..< $0.width)
                }
        }
    }
    
    运行它,每次单击屏幕的黑色部分时,您都会看到两个随机大小和位置的矩形,并在调试窗口中打印输出值​​我们感兴趣

    警告检查打印输出,您会发现错误

    代码是一个错误示例,我把它放在这里是为了证明,您的问题一点也不愚蠢!关于SwiftUI布局及其幕后工作原理,有很多想法需要理解。


    我希望,聪明的人会尝试解释错误,并指导我们如何使其发挥功能,欢迎所有专家!请不要更改RectView,认为它是一些内置的SwiftUI组件。你试过什么吗?至少?我读了很多关于几何读取器等的东西,但还没有找到一个简单的方法。很抱歉如果我的问题看起来很愚蠢。@Asperi请看我的答案:-)尤其是最后一部分。user3441734,谢谢你的建议和解释!对我来说,从这一点出发,走得更远是一个真正的帮助。你能看看我在帖子里的更新吗?我尝试使用矩形数组而不是首选项。它似乎可以工作,代码也比较少,但我很乐意听取您的意见。@Roman preferenceKey方法是正确的方法,一旦您了解了它的工作原理,它就很容易使用。请参阅和下一部分。我的例子表明,边界框和视觉外观可能完全不同。是的,我看到了这种差异,谢谢。但是你也接受数组的用法吗?@Roman:-)你必须喜欢它!代码的异步部分工作正常,我经常使用类似的解决方案。你必须明白它非常脆弱,将来可能会停止工作。使用首选项是有很好的文档记录和解决方案,这与SwiftUI布局所有UI组件的方式非常相似。@Roman我有一个提示,让您解决我示例中的错误。它是在RectView中构建的,它还演示了异步方法脆弱的原因:-)(可能很难找到)
    struct RectView: View {
        let color: Color
        let size = CGFloat(Int.random(in: 50 ... 200))
        var body: some View {
            color.frame(width: size, height: size)
                .alignmentGuide(HorizontalAlignment.center) {
                    CGFloat.random(in: 0 ..< $0.width)
                }
                .alignmentGuide(VerticalAlignment.center) {
                    CGFloat.random(in: 0 ..< $0.width)
                }
        }
    }
    
    struct ContentView: View {
        @State var id = UUID()
        var body: some View {
            VStack {
                ZStack {
                    Color.black
                    RectView(color: .pink)
                        .background(SizeReader())
                    RectView(color: .yellow)
                        .background(SizeReader())
                        .blendMode(.difference)
                }
                .onPreferenceChange(Sizes.self) { (value) in
                    let intersection = value[0].intersection(value[1])
                    print(value[0])
                    print(value[1])
                    print(intersection)
                    print()
                }
                .onTapGesture {
                    self.id = UUID()
                }
                Text("paceholder").id(id)
            }
        }
    }