SwiftUI:如何检测两个视图是否相交?
SwiftUI: How can I detect if two views are intersecting each other?
一个视图与另一个视图相交。我们如何在 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 and 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()
}
}
你的问题一点都不傻!
好像很简单
- 读取第一个视图的帧(在全局坐标中)并将其保存在首选项中
- 读取第二个视图的帧(在全局坐标中)并将其保存在首选项中
- 当偏好改变时计算交集
创建我们的首选项键结构很容易,之前已经在此网站上进行了解释(使用搜索了解更多详细信息:-))
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)])
}
}
}
现在我们可以使用它在我们的尺寸首选项键中保存框架矩形
RectView(color: .pink).background(SizeReader())
我们的 RectView 呢?为了演示我们的 "easy solution" 是如何工作的,假设有人用随机大小和随机对齐方式创建它
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 ..< [=13=].width)
}
.alignmentGuide(VerticalAlignment.center) {
CGFloat.random(in: 0 ..< [=13=].width)
}
}
}
到目前为止一切顺利,我们准备检查我们的 "easy solution"
让我们用
完成我们的项目
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)
}
}
}
运行 它和每次单击屏幕的黑色部分时,您会看到两个大小和位置随机的矩形,并且在调试 window 打印输出中我们感兴趣的值。
警告 检查打印输出,如果有误,您会看到一些东西!
代码是错误的例子,我把它放在这里是为了证明,你的问题一点也不愚蠢!关于 SwiftUI 布局及其在幕后的工作原理,有很多想法需要理解。
希望有高人指点一下问题所在,并指导我们如何让它正常运行,欢迎各位高手!请不要更改 RectView,认为它是一些内置的 SwiftUI 组件
一个视图与另一个视图相交。我们如何在 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 and 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()
}
}
你的问题一点都不傻!
好像很简单
- 读取第一个视图的帧(在全局坐标中)并将其保存在首选项中
- 读取第二个视图的帧(在全局坐标中)并将其保存在首选项中
- 当偏好改变时计算交集
创建我们的首选项键结构很容易,之前已经在此网站上进行了解释(使用搜索了解更多详细信息:-))
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)])
}
}
}
现在我们可以使用它在我们的尺寸首选项键中保存框架矩形
RectView(color: .pink).background(SizeReader())
我们的 RectView 呢?为了演示我们的 "easy solution" 是如何工作的,假设有人用随机大小和随机对齐方式创建它
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 ..< [=13=].width)
}
.alignmentGuide(VerticalAlignment.center) {
CGFloat.random(in: 0 ..< [=13=].width)
}
}
}
到目前为止一切顺利,我们准备检查我们的 "easy solution"
让我们用
完成我们的项目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)
}
}
}
运行 它和每次单击屏幕的黑色部分时,您会看到两个大小和位置随机的矩形,并且在调试 window 打印输出中我们感兴趣的值。
警告 检查打印输出,如果有误,您会看到一些东西!
代码是错误的例子,我把它放在这里是为了证明,你的问题一点也不愚蠢!关于 SwiftUI 布局及其在幕后的工作原理,有很多想法需要理解。
希望有高人指点一下问题所在,并指导我们如何让它正常运行,欢迎各位高手!请不要更改 RectView,认为它是一些内置的 SwiftUI 组件