我有一个UIView
的子类,其中包含一堆使用CGPAth
绘制的图形。我需要知道何时触摸触及这些路径之一,以及哪个路径。
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches {
for p in myDrawnPaths {
if(p.contains(t.location(in: self)) {
doStuffWith(p)
}
}
}
}
有时,这段代码会导致doStuffWith()
在多条路径上执行,包括远离命中位置的路径。我做了一些检查,发现应该受到影响的路径确实有些奇怪:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches {
for p in myDrawnPaths {
print(p.contains(t.location(in: self))) //true
print(p.boundingBox.contains(t.location(in: self))) //false!
}
}
}
嗯?边界框不应该包含整个路径,这意味着路径内的点是否一定在边界框内?
仅在此类测试中出现问题-当我使用CoreGraphics API绘制相同的CGPath
并为其设置动画时,所有显示都是正确的。
更新
我试图在Playgrounds中通过简单的实验路径重现该问题,但是无法做到,所以我不得不从我的实际应用程序中提取这个问题。
(75.0, 264.0) is in
Path 0x600003643960:
moveto (252.02, 287.067)
lineto (259.489, 286.324)
lineto (259.567, 286.754)
lineto (263.438, 286.167)
lineto (268.131, 285.503)
lineto (268.17, 285.268)
lineto (268.248, 284.681)
lineto (269.069, 283.235)
lineto (269.851, 282.57)
lineto (269.773, 280.576)
lineto (270.399, 279.95)
lineto (270.829, 279.833)
lineto (270.907, 278.425)
lineto (271.494, 277.252)
lineto (271.924, 277.486)
lineto (272.002, 277.721)
lineto (272.315, 277.799)
lineto (273.058, 277.408)
lineto (272.901, 273.85)
lineto (271.65, 270.643)
lineto (270.751, 267.085)
lineto (269.812, 265.834)
lineto (268.796, 265.13)
lineto (268.17, 265.56)
lineto (266.645, 266.264)
lineto (265.902, 268.219)
lineto (264.846, 269.666)
lineto (264.416, 269.9)
lineto (263.83, 269.666)
curveto (263.83, 269.666) (262.813, 269.079) (262.891, 268.845)
curveto (262.969, 268.61) (263.087, 266.889) (263.087, 266.889)
lineto (264.416, 266.381)
lineto (264.729, 265.052)
lineto (264.964, 264.035)
lineto (265.902, 263.409)
lineto (265.785, 259.499)
lineto (265.159, 258.6)
lineto (264.651, 258.287)
lineto (264.338, 257.466)
lineto (264.651, 257.153)
lineto (265.276, 257.27)
lineto (265.355, 256.644)
lineto (264.338, 255.784)
lineto (263.83, 254.767)
lineto (262.813, 254.767)
lineto (261.053, 254.181)
lineto (258.903, 252.851)
lineto (257.847, 252.851)
lineto (257.612, 253.086)
lineto (257.221, 252.891)
lineto (256.009, 251.991)
lineto (254.875, 252.695)
lineto (253.741, 253.594)
lineto (253.858, 255.002)
lineto (254.249, 255.119)
lineto (255.07, 255.315)
lineto (255.266, 255.628)
lineto (254.249, 255.941)
lineto (253.233, 256.058)
lineto (252.646, 256.762)
lineto (252.529, 257.583)
lineto (252.646, 258.209)
lineto (252.763, 260.359)
lineto (251.356, 261.18)
lineto (251.121, 261.102)
lineto (251.121, 259.46)
lineto (251.629, 258.521)
lineto (251.864, 257.583)
lineto (251.551, 257.27)
lineto (250.808, 257.583)
lineto (250.417, 259.225)
lineto (249.361, 259.655)
lineto (248.657, 260.398)
lineto (248.579, 260.789)
lineto (248.814, 261.102)
lineto (248.579, 262.119)
lineto (247.68, 262.314)
lineto (247.68, 262.745)
lineto (247.993, 263.683)
lineto (247.563, 266.068)
lineto (246.937, 267.632)
lineto (247.172, 269.47)
lineto (247.367, 269.9)
lineto (247.054, 270.839)
lineto (246.937, 271.152)
lineto (246.82, 272.208)
lineto (248.227, 274.554)
lineto (249.361, 277.095)
lineto (249.948, 278.972)
lineto (249.635, 280.81)
lineto (249.244, 283.156)
lineto (248.306, 285.19)
lineto (248.188, 286.246)
lineto (246.937, 287.458)
closepath
moveto (233.916, 259.147)
moveto (233.407, 258.717)
moveto (232.703, 254.65)
moveto (231.257, 254.142)
moveto (230.592, 253.242)
moveto (225.665, 252.148)
moveto (224.57, 251.717)
moveto (221.403, 250.857)
moveto (218.352, 250.466)
moveto (216.827, 248.394)
moveto (217.101, 248.198)
moveto (218.157, 247.885)
moveto (219.565, 246.986)
lineto (219.565, 246.595)
lineto (219.799, 246.36)
lineto (222.145, 245.969)
lineto (223.084, 245.226)
lineto (224.804, 244.405)
lineto (224.883, 243.897)
lineto (225.626, 242.763)
lineto (226.33, 242.45)
lineto (226.838, 241.746)
lineto (227.737, 240.847)
lineto (229.458, 239.908)
lineto (231.296, 239.713)
lineto (231.726, 240.143)
lineto (231.608, 240.534)
lineto (230.162, 240.925)
lineto (229.575, 242.137)
lineto (228.676, 242.45)
lineto (228.48, 243.388)
lineto (227.542, 244.64)
lineto (227.424, 245.656)
lineto (227.737, 245.852)
lineto (228.128, 245.422)
lineto (229.536, 244.288)
lineto (230.044, 244.796)
lineto (230.944, 244.796)
lineto (232.195, 245.187)
lineto (232.782, 245.617)
lineto (233.368, 246.83)
lineto (234.424, 247.885)
lineto (235.949, 247.807)
lineto (236.535, 247.416)
lineto (237.161, 247.924)
lineto (237.787, 248.12)
lineto (238.295, 247.807)
lineto (238.725, 247.807)
lineto (239.351, 247.416)
lineto (240.915, 246.008)
lineto (242.245, 245.578)
lineto (244.825, 245.461)
lineto (246.585, 244.718)
lineto (247.602, 244.21)
lineto (248.188, 244.288)
lineto (248.188, 246.517)
lineto (248.384, 246.634)
lineto (249.518, 246.947)
lineto (250.261, 246.751)
lineto (252.646, 246.126)
lineto (253.076, 245.696)
lineto (253.663, 245.891)
lineto (253.663, 248.628)
lineto (254.914, 249.84)
lineto (255.422, 250.075)
lineto (255.931, 250.466)
lineto (255.422, 250.583)
lineto (255.109, 250.466)
lineto (253.663, 250.271)
lineto (252.842, 250.505)
lineto (251.942, 250.427)
lineto (250.691, 251.014)
lineto (249.987, 251.014)
lineto (247.719, 250.505)
lineto (245.686, 250.583)
lineto (244.943, 251.6)
lineto (242.205, 251.835)
lineto (241.267, 252.148)
lineto (240.837, 253.36)
lineto (240.328, 253.79)
lineto (240.133, 253.712)
lineto (239.546, 253.086)
lineto (237.787, 254.025)
lineto (237.552, 254.025)
lineto (237.122, 253.399)
lineto (236.809, 253.477)
lineto (236.066, 255.198)
lineto (235.675, 256.762)
lineto (234.424, 259.46)
closepath
moveto (222.849, 237.367)
moveto (223.553, 236.545)
moveto (224.413, 236.233)
moveto (226.525, 234.708)
moveto (227.424, 234.473)
moveto (227.62, 234.668)
moveto (225.626, 236.663)
moveto (224.335, 237.406)
moveto (223.514, 237.758)
closepath
moveto (257.221, 250.31)
moveto (257.456, 251.287)
moveto (258.707, 251.365)
moveto (259.215, 250.896)
curveto (259.215, 250.896) (259.176, 250.31) (259.059, 250.271)
curveto (258.942, 250.192) (258.433, 249.528) (258.433, 249.528)
lineto (257.573, 249.606)
lineto (256.947, 249.684)
lineto (256.83, 250.114)
我们看到,路径中的所有点的X坐标都在200 s之内,但是X坐标为75的点被计算在该路径之内。
如果我在路径上使用close
命令,问题就消失了,但这带来了其他问题:
CGPath的contains
在开放路径上如何工作,以及在哪里记录(如果有的话)?
这为什么会影响contains
方法的结果,而不影响屏幕上显示的内容?例如,如果我告诉相应的CALayer
用某种颜色填充,那么该颜色不会溢出超出其应有的范围。
答案 0 :(得分:1)
在操场上进行了实验后,我发现对于x值大于或等于CGRect.contains(:)
的点,maxX
方法返回false。或大于或等于maxY
的的y值。
事实证明,CGRect的documentation表示类似的内容:
如果点的坐标位于矩形内或最小X或最小Y边上,则认为该点在矩形内。
我认为文档的措辞很差,因为最大X和最大Y边缘的交点不包括相同。
下面是证明这一点的代码:
let rect = CGRect(x: 0, y: 0, width: 200, height: 200)
rect.contains(CGPoint(x: 0, y: 0)) // true
rect.contains(CGPoint(x: rect.midX, y: 0)) // true
rect.contains(CGPoint(x: 0, y: rect.midY)) // true
rect.contains(CGPoint(x: 200, y: 200)) // false
rect.contains(CGPoint(x: 200, y: 0)) // false
rect.contains(CGPoint(x: 0, y: 200)) // false
rect.contains(CGPoint(x: 0, y: rect.maxY)) // false
rect.contains(CGPoint(x: rect.maxX, y: 0)) // false
rect.contains(CGPoint(x: rect.maxX, y: rect.maxY)) // false
rect.maxX // 200
rect.maxY // 200
此外,documentation指出boundingBox
包含路径的所有点,包括贝塞尔曲线和二次曲线的控制点。您可能要改用boundingBoxOfPath
。