在 Swift 中制作按钮的框架为三角形而不是矩形

Making the frame of a button triangle instead of rectangle in Swift

我有一个按钮,里面有一个三角形的图像。如下所示。

这个按钮还有一个三角形的可点击区域。为此,我创建了一个 UIButton class,如下所示。

按钮的可点击区域是三角形,但按钮的边框仍然是矩形。如何使按钮的框架成为三角形?如果有这种方法,我就不会用bezierpath来绘制可点击区域了,因为frame已经是三角形了。

谢谢。

class triangleShapeButton: UIButton {
private let triangle = UIBezierPath()

override func draw(_ rect: CGRect) {
        super.draw(rect)
        triangle.move(to: CGPoint(x: rect.width, y: rect.height))
        triangle.addLine(to: CGPoint(x:rect.width/2, y: 0))
        triangle.addLine(to: CGPoint(x: 0, y:rect.height))
        triangle.close()
    }

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

        // This is for allow touches only in shape area.
        if triangle.contains(touches.first?.location(in: self) ?? .zero) {
            super.touchesBegan(touches, with: event)
         
        }
    }

编辑:我想要创建的是一个圆形按钮设置如下。在这样做的同时,一些三角形按钮的矩形框与下一个三角形按钮重叠。这会导致某些三角形按钮的可点击区域被挡住。我试图更改图层层次结构,但至少有一个按钮仍然与另一个按钮重叠。如果我无法更改框架,如何解决该问题?

非常感谢

我在你现有的代码中添加了一些代码,你可以试试。它可能对你有帮助。 我建议你要求矩形图像。

   class TriangleShapeButton: UIButton {
        
       let triangle = UIBezierPath()
       let triangleLayer = CAShapeLayer()
        
        override func draw(_ rect: CGRect) {
            super.draw(rect)
            triangle.move(to: CGPoint(x: rect.width, y: rect.height))
            triangle.addLine(to: CGPoint(x:rect.width/2, y: 0))
            triangle.addLine(to: CGPoint(x: 0, y:rect.height))
            
            triangleLayer.path = triangle.cgPath
            triangleLayer.fillColor = UIColor.red.cgColor
            self.layer.addSublayer(triangleLayer)
            triangle.close()
        }
        
        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
            // This is for allow touches only in shape area.
            if triangle.contains(touches.first?.location(in: self) ?? .zero) {
                super.touchesBegan(touches, with: event)
                
            }
        }
    }

您改变 UIView 形状的原始方法是不可能的。每个 UIView 都是低级别的矩形,因此在您的情况下相邻的三角形必然重叠。

但是还有一个不同的方法:

您可以为整个圆形视图创建一个 class。在这个 class 中,您修改 drawRect 函数,使各个三角形(或圆弧段)彼此相邻绘制。

在此 class 中,您可以覆盖 touchesBegan 方法。在那里您可以使用 touches.first?.location(in: self) 检查触摸位置。这会给你一个CGPoint。然后你可以手动检查触摸发生在哪个三角形并相应地执行操作。

以下是我的建议:

使用 CAShapeLayers 绘制形状。如果您最终想用图像填充这些形状,请查看设置图层,其中图层的内容是 CGImage。添加另一个 CAShapeLayer 来绘制形状的边框。然后应用 CAShapeLayer 作为蒙版将图像裁剪为 triangle/circle 楔形。

现在,为了弄清楚用户点击了什么: 构建形状路径及其框架矩形的数组。当您在视图中点击时,首先循环遍历矩形数组并找到包含点击点的所有矩形。 (可能不止一个。)

然后遍历矩形中包含抽头的较小数组,并使用 UIBezierPath.contains(point:)CGPath.contains(_:using:transform:) 找出哪些形状实际包含抽头点。

通过首先过滤您的数组以仅显示其帧包含抽头点的那些形状,您可以使用非常快速的测试来减少必须使用慢得多的路径 contains() 方法检查的形状数量。