英文:
Swift iOS: Determine if bezier path intersects with UIView frame?
问题
I've translated the code portion as requested:
我创建了一个自定义的UIView,用于绘制UIBezierPath,并将其分配给CAShapeLayer,然后将其蒙版到UIView的根层。现在我试图确定不同的UIView是否与该自定义视图中的任何部分的贝塞尔路径相交(或重叠),使用以下代码:
let customView = … // 定义UICustomView
let purpleView = UIView(frame: CGRect(x: 30, y: 500, width: 100, height: 50))
purpleView.backgroundColor = UIColor.purple
self.view.addSubview(purpleView)
if purpleView.frame.intersects((customView.shapeLayer.path?.boundingBoxOfPath)!) == true {
print("重叠")
} else {
print("未重叠")
}
唯一的问题是,它只在紫色视图位于部分正方形的左上角时返回true。下面的放置会返回false:
(我希望它在重叠任何绿色部分时返回true,否则返回false。我只绘制了正方形的3个边,并有意留空填充)
以下是自定义视图的代码:
class CustomView : UIView {
private var _path : UIBezierPath!
public let shapeLayer = CAShapeLayer()
override init(frame: CGRect) {
super.init(frame: frame)
self._setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self._setup()
}
private func _setup() {
self._createSquare()
}
private func _createSquare() {
self._path = UIBezierPath()
self._path.move(to: CGPoint(x: 0.0, y: 0.0))
self._path.addLine(to: CGPoint(x: 0.0, y: self.frame.size.height))
self._path.addLine(to: CGPoint(x: self.frame.size.width, y: self.frame.size.height))
self._path.addLine(to: CGPoint(x: self.frame.size.width, y: 0.0))
self.shapeLayer.path = self._path.cgPath
self.shapeLayer.lineWidth = 10
self.shapeLayer.strokeColor = UIColor.green.cgColor
self.backgroundColor = UIColor.green
self.shapeLayer.fillColor = nil
self.layer.mask = self.shapeLayer
}
}
是否有方法可以实现这一目标?我意识到使用frame.intersects()函数可能不是正确的方法。
英文:
I’ve created a custom UIView that draws a UIBezierPath, assigns it to a CAShapeLayer, and then masks it to the UIView’s root layer. Now what I’m trying to do is determine if a different UIView is intersecting (or overlapping) any part of the bezier path in that custom view, using the following code:
let customView = … // define UICustomView
let purpleView = UIView(frame: CGRect(x: 30, y: 500, width: 100, height: 50))
purpleView.backgroundColor = UIColor.purple
self.view.addSubview(purpleView)
if purpleView.frame.intersects((customView.shapeLayer.path?.boundingBoxOfPath)!) == true {
print("Overlapping")
} else {
print("Not overlapping")
}
The only problem is that it only returns true if the purpleView is at the top left of the partial square. The placement below returns false:
(I want it to return true if it’s overlapping any of the green, and false otherwise. I’ve only drawn 3 sides of the square and intentionally left the fill empty)
The following is the code for the custom view
class CustomView : UIView {
private var _path : UIBezierPath!
public let shapeLayer = CAShapeLayer()
override init(frame: CGRect) {
super.init(frame: frame)
self._setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self._setup()
}
private func _setup() {
self._createSquare()
}
private func _createSquare() {
self._path = UIBezierPath()
self._path.move(to: CGPoint(x: 0.0, y: 0.0))
self._path.addLine(to: CGPoint(x: 0.0, y: self.frame.size.height))
self._path.addLine(to: CGPoint(x: self.frame.size.width, y: self.frame.size.height))
self._path.addLine(to: CGPoint(x: self.frame.size.width, y: 0.0))
//self._path.close()
self.shapeLayer.path = self._path.cgPath
self.shapeLayer.lineWidth = 10
self.shapeLayer.strokeColor = UIColor.green.cgColor
self.backgroundColor = UIColor.green
self.shapeLayer.fillColor = nil
self.layer.mask = self.shapeLayer
}
}
Is there a way to make this happen? I realize using the frame.intersects() function might not be the right approach.
答案1
得分: 1
boundBoxOfPath
在 CustomView
的坐标空间中,而 purpleView.frame
在 self.view
的坐标空间中。只有当它们在相同的坐标空间中时,才应该比较路径。UICoordinateSpace
中的各种 convert
方法可用于在坐标空间之间进行转换。
if let pathBounds = customView.shapeLayer.path?.boundingBoxOfPath,
self.view.convert(purpleView.frame, to: customView).intersects(pathBounds) {
print("重叠")
} else {
print("不重叠")
}
请注意,这将检查两个矩形是否重叠。它也将对这种情况返回 true:
绿色 "矩形" 完全覆盖 紫色矩形,这也是一种交集。
如果您只想检查紫色矩形是否与绿色 线条 交叉,您可以从绿色路径创建一个新路径,使其在用绿色填充时的结果与您 描边 绿色路径的结果相同。参见 copy(strokingWithWidth:lineCap:lineJoin:miterLimit:transform:)
。
然后,您可以从 purpleView.frame
创建一个矩形路径,并使用 CGPath.intersects
检查新路径和矩形路径是否相交。
let purpleViewPath = CGPath(rect: self.view.convert(purpleView.frame, to: customView), transform: nil)
if let path = customView.shapeLayer.path?.copy(
strokingWithWidth: customView.shapeLayer.lineWidth,
// 这些是 CGShapeLayer 的默认值。
// 您也可以尝试从 CGShapeLayer 中的相应属性转换这些值
lineCap: .butt,
lineJoin: .miter,
miterLimit: 10
),
purpleViewPath.intersects(path, using: .evenOdd) {
print("重叠")
} else {
print("不重叠")
}
英文:
You are mixing up coordinate spaces. boundBoxOfPath
is in CustomView
's coordinate space, whereas purpleView.frame
is in the coordinate space of self.view
. You should only compare paths when they are in the same coordinate space. The various convert
methods in UICoordinateSpace
can be used to convert between coordinate spaces.
if let pathBounds = customView.shapeLayer.path?.boundingBoxOfPath,
self.view.convert(purpleView.frame, to: customView).intersects(pathBounds) {
print("Overlapping")
} else {
print("Not overlapping")
}
Note that this will check if the two rectangles overlap. It will return true for cases like this too:
The green "rectangle" completely covers the purple rectangle, and that is also a kind of intersection.
If you just want to check if the purple rectangle intersects the green lines, you can create a new path from the green path, such that, when filled with green, the result is the same as if you stroked the green path. See copy(strokingWithWidth:lineCap:lineJoin:miterLimit:transform:)
.
Then, you create a rectangular path from purpleView.frame
, and check if the new path and the rectangular path intersects, using CGPath.intersects
.
let purpleViewPath = CGPath(rect: self.view.convert(purpleView.frame, to: customView), transform: nil)
if let path = customView.shapeLayer.path?.copy(
strokingWithWidth: customView.shapeLayer.lineWidth,
// these are the default values for a CGShapeLayer.
// you can also try converting the values from the corresponding properties in CGShapeLayer
lineCap: .butt,
lineJoin: .miter,
miterLimit: 10
),
purpleViewPath.intersects(path, using: .evenOdd) {
print("Overlapping")
} else {
print("Not overlapping")
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论