仅使 UIBezierPath 按钮内的点可选
make only points within UIBezierPath button selectable
我的 swift 代码具有一个由 UIBezierPath 制作的自定义形状按钮。如果用户触摸红色部分,则代码应仅调用 func press 如果用户触摸绿色部分,则不应调用 func press。现在,如果您触摸绿色部分,函数仍会被调用。
import UIKit
class ViewController: UIViewController {
let customButton = UIButton(frame: CGRect(x: 100.0, y: 100.0, width: 200.0, height: 140.0))
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
customButton.backgroundColor = UIColor.green
let aPath = UIBezierPath()
aPath.move(to: CGPoint(x: 50, y: 0))
aPath.addLine(to: CGPoint(x: 200.0, y: 40.0))
aPath.addLine(to: CGPoint(x: 160, y: 140))
aPath.addLine(to: CGPoint(x: 40.0, y: 140))
aPath.addLine(to: CGPoint(x: 0.0, y: 40.0))
aPath.close()
let layer = CAShapeLayer()
layer.fillColor = UIColor.red.cgColor
layer.strokeColor = UIColor.red.cgColor
layer.path = aPath.cgPath
customButton.layer.addSublayer(layer)
self.view.addSubview(customButton)
customButton.addTarget(self, action: #selector(press), for: .touchDown)
}
@objc func press(){
print("hit")
}
}
首先要为您的自定义按钮添加您的约束,以便试图解决问题的社区能够轻松识别您的问题。例如;
customButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
customButton.widthAnchor.constraint(equalToConstant: 250),
customButton.heightAnchor.constraint(equalToConstant: 100),
customButton.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
customButton.centerYAnchor.constraint(equalTo: self.view.centerYAnchor)
])
你的问题出在你的代码中,你正在向你的图层添加填充,而你的图层已经存在于你的按钮本身中。所以无法识别你的事件响应者,你的功能自然就不起作用了。
yourGreenPartWhichYouClickable.isUserInteractionEnabled = false
yourRedPartWhichYouClickable.isUserInteractionEnabled = false
我的解决方案是将 UIButton
子类化为 FunkyButton
。该按钮包含路径信息。 FunkyButton 覆盖 hitTest(_:event:)
方法,并检查该点是否包含在路径中。
试一试:
class ViewController: UIViewController {
let customButton = FunkyButton(frame: CGRect(x: 100.0, y: 100.0, width: 200.0, height: 140.0))
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
customButton.backgroundColor = UIColor.green
self.view.addSubview(customButton)
customButton.addTarget(self, action: #selector(press), for: .touchDown)
}
@objc func press(){
print("hit")
}
}
class FunkyButton: UIButton {
let aPath = UIBezierPath()
override init (frame : CGRect) {
super.init(frame : frame)
aPath.move(to: CGPoint(x: 50, y: 0))
aPath.addLine(to: CGPoint(x: 200.0, y: 40.0))
aPath.addLine(to: CGPoint(x: 160, y: 140))
aPath.addLine(to: CGPoint(x: 40.0, y: 140))
aPath.addLine(to: CGPoint(x: 0.0, y: 40.0))
aPath.close()
let shapedLayer = CAShapeLayer()
shapedLayer.fillColor = UIColor.red.cgColor
shapedLayer.strokeColor = UIColor.red.cgColor
shapedLayer.path = aPath.cgPath
layer.addSublayer(shapedLayer)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
if self.isHidden == true || self.alpha < 0.1 || self.isUserInteractionEnabled == false {
return nil
}
if aPath.contains(point) {
return self
}
return nil
}
}
我的 swift 代码具有一个由 UIBezierPath 制作的自定义形状按钮。如果用户触摸红色部分,则代码应仅调用 func press 如果用户触摸绿色部分,则不应调用 func press。现在,如果您触摸绿色部分,函数仍会被调用。
import UIKit
class ViewController: UIViewController {
let customButton = UIButton(frame: CGRect(x: 100.0, y: 100.0, width: 200.0, height: 140.0))
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
customButton.backgroundColor = UIColor.green
let aPath = UIBezierPath()
aPath.move(to: CGPoint(x: 50, y: 0))
aPath.addLine(to: CGPoint(x: 200.0, y: 40.0))
aPath.addLine(to: CGPoint(x: 160, y: 140))
aPath.addLine(to: CGPoint(x: 40.0, y: 140))
aPath.addLine(to: CGPoint(x: 0.0, y: 40.0))
aPath.close()
let layer = CAShapeLayer()
layer.fillColor = UIColor.red.cgColor
layer.strokeColor = UIColor.red.cgColor
layer.path = aPath.cgPath
customButton.layer.addSublayer(layer)
self.view.addSubview(customButton)
customButton.addTarget(self, action: #selector(press), for: .touchDown)
}
@objc func press(){
print("hit")
}
}
首先要为您的自定义按钮添加您的约束,以便试图解决问题的社区能够轻松识别您的问题。例如;
customButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
customButton.widthAnchor.constraint(equalToConstant: 250),
customButton.heightAnchor.constraint(equalToConstant: 100),
customButton.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
customButton.centerYAnchor.constraint(equalTo: self.view.centerYAnchor)
])
你的问题出在你的代码中,你正在向你的图层添加填充,而你的图层已经存在于你的按钮本身中。所以无法识别你的事件响应者,你的功能自然就不起作用了。
yourGreenPartWhichYouClickable.isUserInteractionEnabled = false
yourRedPartWhichYouClickable.isUserInteractionEnabled = false
我的解决方案是将 UIButton
子类化为 FunkyButton
。该按钮包含路径信息。 FunkyButton 覆盖 hitTest(_:event:)
方法,并检查该点是否包含在路径中。
试一试:
class ViewController: UIViewController {
let customButton = FunkyButton(frame: CGRect(x: 100.0, y: 100.0, width: 200.0, height: 140.0))
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
customButton.backgroundColor = UIColor.green
self.view.addSubview(customButton)
customButton.addTarget(self, action: #selector(press), for: .touchDown)
}
@objc func press(){
print("hit")
}
}
class FunkyButton: UIButton {
let aPath = UIBezierPath()
override init (frame : CGRect) {
super.init(frame : frame)
aPath.move(to: CGPoint(x: 50, y: 0))
aPath.addLine(to: CGPoint(x: 200.0, y: 40.0))
aPath.addLine(to: CGPoint(x: 160, y: 140))
aPath.addLine(to: CGPoint(x: 40.0, y: 140))
aPath.addLine(to: CGPoint(x: 0.0, y: 40.0))
aPath.close()
let shapedLayer = CAShapeLayer()
shapedLayer.fillColor = UIColor.red.cgColor
shapedLayer.strokeColor = UIColor.red.cgColor
shapedLayer.path = aPath.cgPath
layer.addSublayer(shapedLayer)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
if self.isHidden == true || self.alpha < 0.1 || self.isUserInteractionEnabled == false {
return nil
}
if aPath.contains(point) {
return self
}
return nil
}
}