开发者

Detect touch on UIBezierPath stroke, not fill [duplicate]

This question already has answers here: Closed 10 years ago.

Possible Duplicate:

How can I check if a user tapped near a CGPath?

I'm following Apple's guide from here

http://developer.apple.com/library/ios/#documentation/2DDrawing/Conceptual/DrawingPrintingiOS/BezierPaths/BezierPaths.html

to try and detect a touch event only on the stroked portion of my UIBezierPath.开发者_StackOverflow If I use the UIBezierPath method, containsPoint, it works fine, but it detects touch events on the stroke and the fill portion of the UIBezierPath, and I want it to only occur on the stroked portion.

Following Apple's guide (at listing 3-6 of the link), I created this function:

- (BOOL)containsPoint:(CGPoint)point onPath:(UIBezierPath*)path inFillArea:(BOOL)inFill
{
    CGContextRef context = UIGraphicsGetCurrentContext();    
    CGPathRef cgPath = path.CGPath;    
    BOOL    isHit = NO;

    // Determine the drawing mode to use. Default to    
    // detecting hits on the stroked portion of the path.    
    CGPathDrawingMode mode = kCGPathStroke;    
    if (inFill)        
    {   
        // Look for hits in the fill area of the path instead.
        if (path.usesEvenOddFillRule)
            mode = kCGPathEOFill;
        else
            mode = kCGPathFill;
    }

    // Save the graphics state so that the path can be
    // removed later.
    CGContextSaveGState(context);
    CGContextAddPath(context, cgPath);

   // Do the hit detection.
   isHit = CGContextPathContainsPoint(context, point, mode);
   CGContextRestoreGState(context);
   return isHit;
}

When I call it, I get:

Error: CGContextSaveGState: invalid context 0x0

Error: CGContextAddPath: invalid context 0x0

Error: CGContextPathContainsPoint: invalid context 0x0

Error: CGContextRestoreGState: invalid context 0x0

Here's my view's drawRect function, and my code to create my path:

- (UIBezierPath *) createPath {
    static UIBezierPath *path = nil;
    if(!path) {
        path = [[UIBezierPath bezierPathWithOvalInRect:CGRectMake(35, 45, 250, 250)] retain];
        path.lineWidth = 50.0;
        [path closePath];
    }    
    return path;
}

/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
*/ 
- (void)drawRect:(CGRect)rect
{
    // Drawing code

    //draw a circle
    UIBezierPath *aPath = [self createPath];

    //set stroke width
    aPath.lineWidth = 50.0;

    //set stroke color
    [[UIColor blueColor] setStroke];

    //stroke path
    [aPath stroke];

    //close path
    [aPath closePath];

    //add a label at the "top"
    UILabel *topLabel;
    topLabel = [[UILabel alloc]initWithFrame:CGRectMake(120, -5, 80, 25)];
    topLabel.text = @"The Top";
    [self addSubview:topLabel];
}

I'm then trying to call the containsPoint function inside of touchesMoved, like this:

if (![self containsPoint:c onPath:[self createPath] inFillArea:NO]) return;


When you're currently not drawing (as in the touchesMoved method), there is no current context, so UIGraphicsGetCurrentContext() will return NULL.

As all you're doing with the context is to use its current path, you could just as well use CGPathContainsPoint instead of CGContextPathContainsPoint.


Apple's example assumes you're working inside a graphics context. You're not, so you can just add two lines to the method:

UIGraphicsBeginImageContext(self.frame.size); // ADD THIS...
CGContextRef context = UIGraphicsGetCurrentContext(); // ...before this

and

CGContextRestoreGState(context); // after this...
UIGraphicsEndImageContext(); // ADD THIS

I just ran into the same problem, and this fixed it for me!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜