我正在尝试使用Apples方法来检测点是否在UIBezierPath上。但是它会返回“无效的上下文”。
从NSlog中可以看到,我正在传递一个UIBezierPath和A点来检查。就我而言,是一个接触点。
我不明白为什么。有人可以向我解释或指出我正确的方向吗?
NSLOG -----
Path <UIBezierPath: 0x7f57110>
Contains point Path <UIBezierPath: 0x7f57110>
Touch point 425.000000 139.000000
<Error>: CGContextSaveGState: invalid context 0x0
<Error>: CGContextAddPath: invalid context 0x0
<Error>: CGContextPathContainsPoint: invalid context 0x0
<Error>: CGContextRestoreGState: invalid context 0x0
NO
直接来自Apples文档,了解如何确定路径中的某个点
- (BOOL)containsPoint:(CGPoint)point onPath:(UIBezierPath *)path inFillArea:(BOOL)inFill {
NSLog(@"contains point Path %@", path);
NSLog(@"Touch point %f %f", point.x, point.y );
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;
}
这是我的touchesBegan方法。我在NSMutableArray中有我的路径。我解析数组以检查我的所有路径以查看是否有任何路径。
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint curPoint = [[touches anyObject] locationInView:self];
for (int i = 0; i < [pathInfo count]; i++){
NSArray *row = [[NSArray alloc] initWithArray:[pathInfo objectAtIndex:i]];
UIBezierPath *path = [row objectAtIndex:0];
NSLog(@"Path %@", path);
if ([self containsPoint:curPoint onPath:path inFillArea:NO]){
NSLog(@"YES");
} else {
NSLog(@"NO");
}
}
}
答案 0 :(得分:4)
tl; dr:您应该使用CGPathContainsPoint( ... )
代替。
你的问题是你没有上下文来试图获得它
CGContextRef context = UIGraphicsGetCurrentContext(); // <-- This line here...
如果存在有效的当前上下文,方法UIGraphicsGetCurrentContext
将仅返回上下文。
在drawRect:
内(上下文是您正在绘制的视图)
在您自己的图像上下文中(当您使用UIGraphicsBeginImageContext()
时,您可以使用Core Graphics绘制图像(也许您将其传递给代码的其他部分并将其显示在图像中)查看或保存到磁盘))。
我不知道你为什么要做上下文的所有额外工作,保存和恢复状态等等。我似乎错过了简单的方法CGPathContainsPoint()
。
BOOL isHit = CGPathContainsPoint(
path.CGPath,
NULL,
point,
path.usesEvenOddFillRule
);
如果你想测试一个笔划路径你可以使用CGPathCreateCopyByStrokingPath()
来首先创建一个你正在抚摸的路径的新填充路径(给定一定的宽度等)。 Ole Begemann有a very good explanation on his blog关于如何做到这一点(包括一些示例代码)。
答案 1 :(得分:4)
CGContextPathContainsPoint
方法需要图形上下文,Apple的示例代码来自UIGraphicsGetCurrentContext
。但是,UIGraphicsGetCurrentContext
仅适用于-[UIView drawRect:]
内部或调用设置UI图形上下文的函数后,例如UIGraphicsBeginImageContext
。
使用CGPathCreateCopyByStrokingPath
(在iOS 5.0中添加)和CGPathContainsPoint
在描边副本上,您可以在没有图形上下文的情况下执行命中测试:
static BOOL strokedPathContainsPoint(CGPathRef unstrokedPath,
const CGAffineTransform *transform, CGFloat lineWidth,
CGLineCap lineCap, CGLineJoin lineJoin, CGFloat miterLimit,
CGPoint point, bool eoFill)
{
CGPathRef strokedPath = CGPathCreateCopyByStrokingPath(unstrokedPath,
transform, lineWidth, lineCap, lineJoin, miterLimit);
BOOL doesContain = CGPathContainsPoint(strokedPath, NULL, point, eoFill);
CGPathRelease(strokedPath);
return doesContain;
}
您必须决定要使用的线宽和其他描边参数。例如:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint curPoint = [[touches anyObject] locationInView:self];
for (int i = 0; i < [pathInfo count]; i++){
NSArray *row = [[NSArray alloc] initWithArray:[pathInfo objectAtIndex:i]];
UIBezierPath *path = [row objectAtIndex:0];
NSLog(@"Path %@", path);
if (strokedPathContainsPoint(path.CGPath, NULL, 10.0f, kCGLineCapRound,
kCGLineJoinRound, 0, curPoint, path.usesEvenOddFillRule))
{
NSLog(@"YES");
} else {
NSLog(@"NO");
}
}
}
请注意,CGPathCreateCopyByStrokingPath
可能有些昂贵,因此您可能需要对路径进行一次描边,并保存描边副本,而不是每次需要测试点时都要对它们进行描边。