Detecting tap inside a bezier path

2020-02-06 06:08发布

I have a UIView which is added as a subview to my view controller. I have drawn a bezier path on that view. My drawRect implementation is below

- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();
    UIBezierPath *bpath = [UIBezierPath bezierPath];

    [bpath moveToPoint:CGPointMake(50, 50)];
    [bpath addLineToPoint:CGPointMake(100, 50)];
    [bpath addLineToPoint:CGPointMake(100, 100)];
    [bpath addLineToPoint:CGPointMake(50, 100)];
    [bpath closePath];

    CGContextAddPath(context, bpath.CGPath);
    CGContextSetStrokeColorWithColor(context,[UIColor blackColor].CGColor);
    CGContextSetLineWidth(context, 2.5);
    CGContextStrokePath(context);
    UIColor *fillColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.5 alpha:0.7];
    [fillColor setFill];
    [bpath fill];
}

I want detect tap inside this bezier path but not the point which is inside the UIView and outside the path. For example in this case if my touch coordinate is (10, 10), it should not be detected. I know about CGContextPathContainsPoint but it does not help when touch is inside the path. Is there a way to detect touch events inside bezier path?

4条回答
虎瘦雄心在
2楼-- · 2020-02-06 06:14

Try UIBezierPath's method :

func contains(_ point: CGPoint) -> Bool

Returns a Boolean value indicating whether the area enclosed by the receiver contains the specified point.

查看更多
成全新的幸福
3楼-- · 2020-02-06 06:15

There is a function CGPathContainsPoint() it may be useful in your case.

Also be careful if you get gesture point from superview, the coordinate may not be correct with your test. You have a method to convertPoint from or to a particular view's coordinate system:

- (CGPoint)convertPoint:(CGPoint)point toView:(UIView *)view
- (CGPoint)convertPoint:(CGPoint)point fromView:(UIView *)view
查看更多
闹够了就滚
4楼-- · 2020-02-06 06:18

A solution in Swift 3.1 (porting over the Apple recommended solution from here)

func containsPoint(_ point: CGPoint, path: UIBezierPath, inFillArea: Bool) -> Bool {

        UIGraphicsBeginImageContext(self.size)

        let context: CGContext? = UIGraphicsGetCurrentContext()
        let pathToTest = path.cgPath
        var isHit = false

        var mode: CGPathDrawingMode = CGPathDrawingMode.stroke

        if inFillArea {

            // check if UIBezierPath uses EO fill
            if path.usesEvenOddFillRule {
                mode = CGPathDrawingMode.eoFill
            } else {
                mode = CGPathDrawingMode.fill
            }
        } // else mode == stroke

        context?.saveGState()
        context?.addPath(pathToTest)

        isHit = (context?.pathContains(point, mode: mode))!
        context?.restoreGState()

        return isHit
        }
查看更多
Fickle 薄情
5楼-- · 2020-02-06 06:25

Detecting tap inside a bezier path in swift :-

It's simple in latest swift ,follow these steps and you will get your UIBezierPath touch event.

Step 1 :- Initialize Tap Event on view where your UIBeizerPath Added.

///Catch layer by tap detection let tapRecognizer:UITapGestureRecognizer = UITapGestureRecognizer.init(target: self, action: #selector(YourClass.tapDetected(_:))) viewSlices.addGestureRecognizer(tapRecognizer)

Step 2 :- Make "tapDetected" method

  //MARK:- Hit TAP
public func tapDetected(tapRecognizer:UITapGestureRecognizer){
    let tapLocation:CGPoint = tapRecognizer.locationInView(viewSlices)
    self.hitTest(CGPointMake(tapLocation.x, tapLocation.y))


}

Step 3 :- Make "hitTest" final method

  public func hitTest(tapLocation:CGPoint){
        let path:UIBezierPath = yourPath
        if path.containsPoint(tapLocation){
            //tap detected do what ever you want ..;)
        }else{
             //ooops you taped on other position in view
        }
    }



Update: Swift 4

Step 1 :- Initialize Tap Event on view where your UIBeizerPath Added.

///Catch layer by tap detection
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(YourClass.tapDetected(tapRecognizer:)))
viewSlices.addGestureRecognizer(tapRecognizer)

Step 2 :- Make "tapDetected" method

public func tapDetected(tapRecognizer:UITapGestureRecognizer){
    let tapLocation:CGPoint = tapRecognizer.location(in: viewSlices)
    self.hitTest(tapLocation: CGPoint(x: tapLocation.x, y: tapLocation.y))
}

Step 3 :- Make "hitTest" final method

private func hitTest(tapLocation:CGPoint){
    let path:UIBezierPath = yourPath

    if path.contains(tapLocation){
        //tap detected do what ever you want ..;)
    }else{
        //ooops you taped on other position in view
    }
}
查看更多
登录 后发表回答