SwiftUI:如何检测两个视图是不是相互交叉?
Posted
技术标签:
【中文标题】SwiftUI:如何检测两个视图是不是相互交叉?【英文标题】:SwiftUI: How can I detect if two views are intersecting each other?SwiftUI:如何检测两个视图是否相互交叉? 【发布时间】:2020-02-26 05:06:22 【问题描述】:一个视图与另一个视图相交。我们如何在 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 无关:我们这里有另一个框架概念。什么可以代替?有人有想法吗?
更新:
非常感谢user3441734 和Asperi 的帮助和建议! 这是我使用矩形数组解决问题的尝试:
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()
【问题讨论】:
很多。你有什么尝试吗?至少this? 我读了很多关于几何阅读器等的东西,但还没有找到一个简单的方法来做到这一点。对不起;如果我的问题看起来很愚蠢。 @Asperi 请看我的回答 :-) 尤其是最后一部分。 【参考方案1】:你的问题一点都不傻!
好像很简单
-
读取第一个视图的帧(在全局坐标中)并将其保存在首选项中
读取第二个视图的帧(在全局坐标中)并将其保存在首选项中
当偏好改变时计算交点
创建我们的偏好键结构很容易,之前已经在此网站上解释过(使用搜索了解更多详细信息:-))
struct Sizes: PreferenceKey
typealias Value = [CGRect]
static var defaultValue: [CGRect] = []
static func reduce(value: inout [CGRect], nextValue: () -> [CGRect])
value.append(contentsOf: nextValue())
在后台视图修改器中使用 GeometryReader 已经解释过
struct SizeReader: View
var body: some View
GeometryReader proxy in
Color.clear
.preference(key: Sizes.self, value: [proxy.frame(in: .global)])
现在我们可以使用它在我们的 Sizes 首选项键中保存框架矩形
RectView(color: .pink).background(SizeReader())
我们的 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)
运行它,每次单击屏幕的黑色部分时,您都会看到两个随机大小和定位的矩形,并在调试窗口中打印出我们感兴趣的值。
警告检查打印输出,如果有问题,您会发现!
代码是错误的例子,我把它放在这里是为了证明你的问题一点也不愚蠢!关于 SwiftUI 布局及其在幕后的工作原理,有很多想法需要了解。
我希望,聪明的人会尝试解释问题所在,并指导我们如何使其发挥作用,欢迎所有专家!请不要更改 RectView,认为它是一些内置的 SwiftUI 组件
【讨论】:
user3441734,感谢您的建议和解释!从这一点开始并走得更远,对我来说是一个真正的帮助。你能看看我在帖子中的更新吗?我尝试使用矩形数组而不是首选项键。它似乎可以工作并且代码更少,但我很乐意听取您的意见。 @Roman preferenceKey 方法是正确的方法,一旦你了解它的工作原理,它就很容易使用。请参阅swiftui-lab.com/communicating-with-the-view-tree-part-1 和下一部分。我的示例表明,边界框和视觉外观可能完全不同。 是的,我看到了这种差异,谢谢。但是你也接受数组的用法吗? @Roman :-) 你必须喜欢它!您代码的异步部分有效,我不时使用类似的解决方案。您必须了解它非常脆弱,将来可能会停止工作。使用偏好是有据可查的可靠解决方案,这与 SwiftUI 用于布局所有 UI 组件的方式非常相似。 @Roman 我有一个提示让你解决我示例中的错误。它是在 RectView 中构建的,它还说明了为什么异步方法很脆弱 :-)(而且可能很难找到)以上是关于SwiftUI:如何检测两个视图是不是相互交叉?的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI实现不同TabView标签页中任意导航层级视图之间自动相互跳转那些事儿