从已定义的贝塞尔路径创建 UIbutton?

Posted

技术标签:

【中文标题】从已定义的贝塞尔路径创建 UIbutton?【英文标题】:Creating a UIbutton from an already defined Bezier Path? 【发布时间】:2019-03-02 14:39:31 【问题描述】:

我在一个视图控制器(默认)中有一系列定义的贝塞尔路径。然而,具体来说,我想让其中一个成为 UIButton (它还不必引导到任何地方,但如果它可以在触摸时打印一些东西会很棒)。

通过查看一些类似的问题,我已经能够在模拟器上分别定义我想要的Bezier Path和UIButton,但无法将它们拼接在一起。

import UIKit

class ViewController: UIViewController 

    override func viewDidLoad() 
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

    let circlePath = UIBezierPath(arcCenter: CGPoint(x: 200, y: 350), radius: CGFloat(150), startAngle: CGFloat(0), endAngle:CGFloat(Double.pi * 2), clockwise: true)

    let shapeLayer = CAShapeLayer()
    shapeLayer.path = circlePath.cgPath

    //change the fill color
    shapeLayer.fillColor = UIColor.clear.cgColor
    //you can change the stroke color
    shapeLayer.strokeColor = UIColor.gray.cgColor
    //you can change the line width
    shapeLayer.lineWidth = 7.5

    view.layer.addSublayer(shapeLayer)

  let button = UIButton(frame: CGRect(x: 100, y: 100, width: 100, height: 50))
        button.backgroundColor = .green
        button.setTitle("Test Button", for: .normal)
        button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)

        self.view.addSubview(button)
    

    @objc func buttonAction(sender: UIButton!) 
        print("Button tapped")
    


如何将 circlePath 作为 UIButton 传递?

【问题讨论】:

【参考方案1】:

UIButton 是 UIView,因此您可以将创建的层添加到按钮中,方法与创建视图的方式相同:

button.layer.addSublayer(shapeLayer)

请注意,该层将覆盖 UIButton 的标签,但解决此问题的一种简单方法是更改​​该层的 z 位置:

shapeLayer.zPosition = -1

例如如果你想给一个按钮添加一个圆形层:

let circlePath = UIBezierPath(ovalIn: button.bounds)
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.cgPath
shapeLayer.zPosition = -1   
button.layer.addSublayer(shapeLayer)

或者,匹配示例中的圆圈,但在形状之前创建按钮:

// define circle parameters
let radius: CGFloat = 150
let center = CGPoint(x: 200, y: 350)

// create the button
let button = UIButton(frame: CGRect(origin: center.applying(CGAffineTransform(translationX: -radius, y: -radius)),
                                        size: CGSize(width: 2 * radius, height: 2 * radius)))

// create the circle layer
let circlePath = UIBezierPath(ovalIn: button.bounds)
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.cgPath
shapeLayer.zPosition = -1

// add the circle layer to the button
button.layer.addSublayer(shapeLayer)

view.addSubview(button)

【讨论】:

感谢您的回答。我不得不切换按钮的位置和路径以使其运行。但是,每当我点击原始按钮所在的位置而不是圆形层时,我只会收到“按下按钮”消息。我正在尝试使圆形图层成为视图上的唯一按钮 - 如果我不清楚,请见谅! 是的,按钮的框架和图层的框架可能不同。 UIBezierPath(ovalIn: button.bounds) 创建一个路径,当分配给按钮时,该路径位于按钮内部。您是否有特殊原因要先声明路径,然后声明按钮,而不是相反? 它是这样出来的,因为我不太了解。我更专注于(可能是不必要的)路径,因为我只希望路径的笔触响应触摸,而不是整个圆。我也希望设置,以便我以后可以将动画渐变应用到路径的笔划 啊,所以你想要一个响应触摸的路径? UIButton 真的不适合那个,这可能是导致混乱的原因。您应该寻找询问“如何检测 CGPath 上的触摸”的问题或自己创建一个。 正是这样 - 我的含糊不清。我会这样做的。谢谢普里贝

以上是关于从已定义的贝塞尔路径创建 UIbutton?的主要内容,如果未能解决你的问题,请参考以下文章

Flutter BottomAppBar 自定义路径 + 贝塞尔曲线实现闲鱼底部导航

通过循环 drawRect 动画自定义贝塞尔路径

从简单的图像 ios 创建贝塞尔路径

使用贝塞尔路径作为剪贴蒙版

以曲线形状剪切贝塞尔路径

在两个贝塞尔路径形状之间制作动画