2009-07-17 34 views
9

Kịch bản:Làm cách nào để kiểm tra xem người dùng có chạm vào một CGPath không?

Tôi có một bộ CGPath s. Chúng chủ yếu là các đường thẳng (nghĩa là các hình dạng không đóng). Chúng được vẽ trên màn hình theo phương pháp vẽ của UIView.

Làm cách nào để kiểm tra xem người dùng có chạm vào một trong các đường dẫn không?

Dưới đây là những gì tôi đã làm việc:

UIGraphincsBeginImageContext(CGPathGetBoundingBox(path)); 
CGContextRef g = UIGraphicsGetCurrentContext(); 
CGContextAddPath(g,path); 
CGContextSetLineWidth(g,15); 
CGContextReplacePathWithStrokedPath(g); 
CGPath clickArea = CGContextCopyPath(g); //Not documented 
UIGraphicsEndImageContext(); 

Vì vậy, những gì tôi đang làm là tạo ra một bối cảnh hình ảnh, bởi vì nó có chức năng tôi cần. Sau đó tôi thêm đường dẫn đến ngữ cảnh và thiết lập chiều rộng của đường là 15. Stroking đường dẫn tại điểm này sẽ tạo vùng nhấp mà tôi có thể kiểm tra bên trong để tìm các lần nhấp. Vì vậy, tôi nhận được rằng con đường vuốt ve bằng cách nói cho bối cảnh để biến con đường thành một con đường vuốt ve, sau đó sao chép đường dẫn đó trở lại vào một CGPath khác. Sau đó, tôi có thể kiểm tra:

if (CGPathContainsPoint(clickArea,NULL,point,NO)) { ... 

Tất cả đều hoạt động tốt và tốt, nhưng CGContextCopyPath, là không có giấy tờ, dường như là một ý tưởng tồi để sử dụng vì lý do rõ ràng. Ngoài ra còn có một kludginess nhất định về việc thực hiện một CGContext chỉ cho mục đích này.

Vì vậy, không ai có bất kỳ ý tưởng nào? Làm cách nào để kiểm tra xem người dùng đã nhấn gần (trong trường hợp này, trong vòng 15 pixel) của bất kỳ khu vực nào trên CGPath?

Trả lời

18

Trong iOS 5.0 và sau đó, điều này có thể được thực hiện đơn giản hơn sử dụng CGPathCreateCopyByStrokingPath:

CGPathRef strokedPath = CGPathCreateCopyByStrokingPath(path, NULL, 15, 
    kCGLineCapRound, kCGLineJoinRound, 1); 
BOOL pointIsNearPath = CGPathContainsPoint(strokedPath, NULL, point, NO); 
CGPathRelease(strokedPath); 

if (pointIsNearPath) ... 
+2

Trong Swift 3.0: 'path.copy (strokingWithWidth: CGFloat…)' – buildsucceeded

2

Vâng, tôi đã tìm ra câu trả lời. Nó sử dụng CGPathApply:

clickArea = CGPathCreateMutable(); 
CGPathApply(path,clickArea,&createClickArea); 

void createClickArea (void *info, const CGPathElement *elem) { 
    CGPathElementType type = elem->type; 
    CGMutablePathRef path = (CGMutablePathRef)info; 
    static CGPoint last; 
    static CGPoint subpathStart; 
    switch (type) { 
    case kCGPathElementAddCurveToPoint: 
    case kCGPathElementAddQuadCurveToPoint: 
     break; 
    case kCGPathElmentCloseSubpath: 
    case kCGPathElementMoveToPoint: { 
     CGPoint p = type == kCGPathElementAddLineToPoint ? elem->points[0] : subpathStart; 
     if (CGPointEqualToPoint(p,last)) { 
     return; 
     } 
     CGFloat rad = atan2(p.y - last.y, p.x - last.x); 
     CGFloat xOff = CLICK_DIST * cos(rad); 
     CGFloat yOff = CLICK_DIST * sin(rad); 
     CGPoint a = CGPointMake(last.x - xOff, last.y - yOff); 
     CGPoint b = CGPointMake(p.x + xOff, p.y + yOff); 
     rad += M_PI_2; 
     xOff = CLICK_DIST * cos(rad); 
     yOff = CLICK_DIST * sin(rad); 
     CGPathMoveToPoint(path, NULL, a.x - xOff, a.y - yOff); 
     CGPathAddLineToPoint(path, NULL, a.x + xOff, a.y + yOff); 
     CGPathAddLineToPoint(path, NULL, b.x + xOff, b.y + yOff); 
     CGPathAddLineToPoint(path, NULL, b.x - xOff, b.y - yOff); 
     CGPathCloseSubpath(path); 
     last = p; 
     break; } 
    case kCGPathElementMoveToPoint: 
     subpathStart = last = elem->points[0]; 
     break; 
    } 
} 

Về cơ bản nó chỉ là phương pháp riêng của tôi cho ReplacePathWithStrokedPath, nhưng nó chỉ hoạt động với các dòng ngay bây giờ.

+0

Cảm ơn rất nhiều đã gửi bài này! bản thân tôi sẽ không có một đầu mối về nó. Mặc dù câu trả lời được chấp nhận hoạt động tốt, nhưng chức năng này về cơ bản đã lưu tôi vì nó mang lại cho bạn sự linh hoạt - tôi có thể xử lý các phần tử đường dẫn khác nhau: chính xác những gì tôi cần. Cảm ơn một lần nữa! – user1244109

Các vấn đề liên quan