How to create custom form button with non-clickable rectangle area in swift?

585 Views Asked by At

Here is my Button class.

@IBDesignable
class Button: UIButton {
    var cornerRadii = CGSize()

    @IBInspectable var cornerRadius: CGFloat = 0 {
        didSet {
            cornerRadii = CGSize(width: cornerRadius, height: cornerRadius)
        }
    }

    @IBInspectable var color: UIColor = .green

    override func draw(_ rect: CGRect) {
        super.draw(rect)

        let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: [.topLeft, .topRight], cornerRadii: cornerRadii)
        let shapeLayer = CAShapeLayer()
        shapeLayer.frame = self.layer.bounds
        shapeLayer.path = path.cgPath
        layer.mask = shapeLayer
        color.setFill()
        path.fill()
    }
}

So everything works pretty well. My button has a half-circe form so actually when I click at the empty corner of the button frame I do not expect it to be pressed, but it actually happens. I thought that mask can help me with this issue but I didn't manage do make it.

So the questing how I can create a button with two empty corners that are not clickable?

3

There are 3 best solutions below

0
On BEST ANSWER

Ovveride point inside method for your custom Button:

override public func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
    let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: [.topLeft, .topRight], cornerRadii: cornerRadii)
    return path.contains(point)
}
0
On

You can override whitest method and check if touch point is inside your bazier path or not. You can check path.containsPoint(point); to find if its inside. If its inside return self or nil.

0
On

As from the comments you can override the hit test method on the button.

This works for me if you need to disable the touches outside the path:

class Button: UIButton {
    var cornerRadii = CGSize()

    @IBInspectable var cornerRadius: CGFloat = 0 {
        didSet {
            cornerRadii = CGSize(width: cornerRadius, height: cornerRadius)
        }
    }

    @IBInspectable var color: UIColor = .green

    var currentPath: UIBezierPath?

    override func draw(_ rect: CGRect) {
        super.draw(rect)


        let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: [.topLeft, .topRight], cornerRadii: cornerRadii)
        currentPath = path // Save the path here to be used in hit test


        let shapeLayer = CAShapeLayer()
        shapeLayer.frame = self.layer.bounds
        shapeLayer.path = path.cgPath
        layer.mask = shapeLayer
        color.setFill()
        path.fill()
    }

    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {

        // check if point is outside the given path and return nil in that case. Otherwise return super
        if currentPath?.contains(point) == false {
            return nil
        } else {
            return super.hitTest(point, with: event)
        }
    }
}