Austin Wood
Austin Wood

Reputation: 378

Gesture recognizer on a circular view

In each cell of my collection view is a circular UIView. This has been achieved by creating a custom subclass of UIView, which I have called CircleView, and setting layer.cornerRadius = self.frame.size.width/2 in the subclass' awakeFromNib()

I want to add a gesture recognizer to each CircleView. I have done this in the collection view's cellForItemAtIndexPath:

let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(tap(_:)))
cell.circleView.addGestureRecognizer(gestureRecognizer)

The problem is that the gesture recognizer is called whenever a tap occurs anywhere within the bounds of the original square UIView. I want to only recognize taps that occur within the circle.

I have tried to solve this issue in the following ways:

In the CircleView's awakeFromNib() I set self.clipsToBounds = true (no effect)

Also in the CircleView's awakeFromNib() I set layer.masksToBounds = true (no effect)

Thank you in advance for your ideas and suggestions.

Upvotes: 3

Views: 1054

Answers (1)

alexburtnik
alexburtnik

Reputation: 7741

You can override this method in CircleView:

override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
    let center = CGPoint(x: bounds.size.width/2, y: bounds.size.height/2)
    return pow(center.x-point.x, 2) + pow(center.y - point.y, 2) <= pow(bounds.size.width/2, 2)
}

enter image description here

All touches not belonging to the circle will be ignored.

More details:

https://developer.apple.com/reference/uikit/uiview/1622469-hittest https://developer.apple.com/reference/uikit/uiview/1622533-point

The main point is that you don't need to call neither hitTest nor pointInside methods, you just override them in your custom view and system will call them whenever it needs to know if a touch should be handled by this view.

In your case you've got a UITableViewCell with a CircleView in it, right? You've added a gesture recognizer to CircleView and overriden pointInside method, so a touch will be handled by CircleView itself if a touch point is inside the circle, otherwise event will be passed further, handled by cell and therefore didSelectRowAtIndexPath will be called.

Upvotes: 12

Related Questions