最近一个朋友在做图片处理的 App,想要实现类似 MOLDIV App
拼图的UI
效果(如何创建不规则的 view
),就问我有什么想法。我首先想到的就是 UIBezierPath
+CAShapeLayer
的方式,为了验证自己的想法,写了一个小 demo
。
效果图:
![](https://i-blog.csdnimg.cn/blog_migrate/d4f2879c2ab0f0660473dd35bd61b01c.webp?x-image-process=image/format,png)
demo.gif
实现思路
正常情况下我们创建的 view
都是矩形的。但是我们知道 view
的内容显示靠的是 layer
层,所以可以通过修改 layer
层来实现。代码如下:
func drawMaskLayer() {
guard (points != nil) else {
return
}
let bezierPath1 = UIBezierPath()
bezierPath1.move(to: points![0])
for index in 1..<points!.count {
bezierPath1.addLine(to: points![index])
}
bezierPath1.addLine(to: points![0])
let shapeLayer = CAShapeLayer()
shapeLayer.path = bezierPath1.cgPath
self.layer.mask = shapeLayer
}
通过这种方式我们可以创建出任何的多边形的 view
。通过这种方式我们可以很容易的创建出上图所示的 UI
布局。但是我们这个时候会发现,当有触摸点在 view
透明的地方时,触摸事件并不能传递给被它遮挡的 view
上,所以需要重写 func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView?
方法来判断何时响应。代码如下:
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
if points != nil {
if (super.hitTest(point, with: event) == scrollV) {
print(self,point)
print(points!)
let isInner = isInnerView(with: point)
if isInner {
return self.scrollV
}else {
return nil
}
}
}else {
return super.hitTest(point, with: event)
}
return nil
}
那么何时响应,何时不响应呢?应该是如果触摸点在我们绘制的 view
范围内响应,之外的不相应。那么这个时候就需要判断一个点在是否在多边形内,本 demo 使用 射线法。
fileprivate func isInnerView(with point: CGPoint) -> Bool {
let pX = point.x , pY = point.y
var flag = false
var oldIndex = points!.count - 1
for newIndex in 0..<points!.count {
let newX = points![newIndex].x
let newY = points![newIndex].y
let oldX = points![oldIndex].x
let oldY = points![oldIndex].y
// 点与多边形顶点重合
if (pX == newX && pY == newY) || (pX == oldX && pY == oldY) {
return false
}
// 判断线段两端点是否在射线两侧
if (oldY > pY && newY < pY) || (oldY < pY && newY > pY) {
// 线段上与射线 Y 坐标相同的点的 X 坐标
let x = newX + (pY - newY) * (oldX - newX) / (oldY - newY)
// 点在多边形的边上
if(x == pX) {
return false
}
// 射线穿过多边形的边界
if(x > pX) {
flag = !flag
}
}
oldIndex = newIndex
}
// 射线穿过多边形边界的次数为奇数时点在多边形内
return flag ? true : false
}
到了这里 demo
也就基本完成了。希望对需要的人有帮助,有什么不对的欢迎指正。
源代码:
ZCFJointView
环境:
Xcode 8.2 、Swift 3.0
参考资料:
射线法