【问题标题】:Making the frame of a button triangle instead of rectangle in Swift在 Swift 中制作按钮三角形而不是矩形的框架
【发布时间】:2021-02-27 17:08:00
【问题描述】:

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

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

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

谢谢。

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)
         
        }
    }

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

非常感谢

【问题讨论】:

  • UIBezierPath 中有一个方法contains(CGPoint)。你可以尝试一次。 developer.apple.com/documentation/uikit/uibezierpath/…
  • UIView 的frame 属性始终是CGRect,因此是矩形的。因此,不可能将 UIButton 的框架设置为三角形。但这从一开始就不应该是必要的。正如您已经发现的那样,您可以在矩形框架内绘制一个自定义三角形。
  • 感谢您的回答。这意味着很多。 @JoRa 我试图解释的内容对于 cmets 来说太长了,所以我编辑了我的问题,哈哈。你能检查一下吗?谢谢
  • @ChanOnly123 是否有与 contains(CGPoint) 完全相反的方法?像“排除”这样的东西:D我找不到这样的东西。谢谢
  • @matt 在您发表评论后,我进行了一些研究。 hitTest 可能是解决方案。但是 hitTest 需要一个 CGPoint 从可触摸区域中排除。而我需要的是要排除的区域。如何定义要排除的区域(作为 CGPoint)? ++我使用 BezierPath 绘制该区域,并尝试将其从可触摸区域中排除。然后尝试类似: if point != newBezierPath return nil。但那里没有任何改变。接下来我该怎么办?我的问题可能很无知。对不起:)

标签: swift xcode uibutton core-animation uibezierpath


【解决方案1】:

以下是我的建议:

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

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

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

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

【讨论】:

    【解决方案2】:

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

       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)
                    
                }
            }
        }
    

    【讨论】:

    • 您的代码所做的是创建一个三角形 CAShapeLayer。我已经有一个三角形按钮。我需要的是更改框架或裁剪框架的某些部分。谢谢
    【解决方案3】:

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

    但是有一种不同的方法:

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

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

    【讨论】:

    • 我一直在考虑你的方法。在这种情况下,我必须自己绘制三角形并自定义它们的外观。在这里,在我的示例中,我确实在 Adob​​ePhotoshop 中绘制了这些三角形并将它们保存为 png 以便能够在 UI 按钮内部使用。如果我自己画了三角形,可以在这些三角形中添加一些 png 图像吗?希望我的方法正确。谢谢。
    • 这是可能的,但我必须自己做一些研究。但肯定有一种方法可以在 drawRect() 中绘制 png 图像。但形状似乎没有那么复杂。有内置的UIBezierPath 方法来绘制弧段,可以设置填充颜色或添加渐变层。所以自己画形状可能更简单
    猜你喜欢
    • 1970-01-01
    • 2014-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-02
    • 2016-08-20
    • 2019-02-27
    相关资源
    最近更新 更多