1

I have been banging my head on this for hours. I tried to read up and searched for answers. I even tried the "walk-away-and-come-back-to-it-later" approach, it didn't work. I even tried Yoga and meditated! I didn't prevail..

So please enlighten me, experts.

All I am trying to get a copy of CGPath not inside drawRect:

CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, ......);
CGPathAddLineToPoint(path, ....);
CGPathAddLineToPoint(path, ....);
CGPathAddLineToPoint(path, ....);
CGPathAddLineToPoint(path, ....);

And finally:
CGPathCloseSubpath(path);
CGContextAddPath(context, path);
That didn't work, so I tried also using instead of the 2 calls above: CGPathCreateMutableCopy(path);
And eventually - I just want to be able to get this path and insert it as path in CAShapeLayer and animate it by making this call:

animation.toValue = [UIBezierPath bezierPathWithCGPath:path];

So before I'd try to take up another relaxing activity such as Sky Diving without a parachute in hopes to clear my mind and finally be able to get this right, could you please help me here by showing me some examples? In addition to that, can you explain to me in detail the correct way using the following functions:

CGPathCloseSubpath(path);
CGContextAddPath(context, path);
CGPathCreateMutableCopy(path);

Thanks in advance.

4

1 に答える 1

0
  • CGPath は、C スタイルの API を使用した C スタイルのデータ構造です。基本的には、パスを構成するポイントのリストです。

  • CGContext は、ポイントを色付きのピクセルに変換する、画像を描画するための C スタイルのデータ構造 (おそらく少し大きい) でもあります。

スニペットを関数に入れ、コピーして 1 つの画面の xcode プロジェクトに貼り付けるだけです。コード内のコメントとして説明があり、CGPath オブジェクトを詳細にデバッグおよび調査するための 2 つの関数があります ( https://github.com/erica/iOS-6-Cookbookから一部を追加して取得しました)。

#import "ViewController.h"
#import "OverlayView.h"
#import <QuartzCore/QuartzCore.h>

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    // create a graphics context with the C-API of the QuartzCore framework
    // the graphics context is only required for drawing the path
    CGRect compositionBounds = CGRectMake(30, 30, 300, 508);
    UIGraphicsBeginImageContext(compositionBounds.size);
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    // create a mutable path with QuartzCore
    CGMutablePathRef p1 = CGPathCreateMutable();

    // create a CGPath with UIKit classes using Obj-C
    UIBezierPath *bp = [UIBezierPath bezierPath];
    [bp moveToPoint:(CGPoint){180, 120}];
    [bp addLineToPoint:(CGPoint){30, 170}];
    [bp addLineToPoint:(CGPoint){135, 175}];
    [bp addLineToPoint:(CGPoint){105, 115}];
    // if you fill the path during drawing it gets closed implicitly
//    [bp closePath];
    // add the CGPath to our mutable path
    CGPathAddPath(p1, nil, bp.CGPath);

    // add a closed triangle as subpath to our mutable path
    CGPathMoveToPoint(p1, nil, 50, 250);
    CGPoint p2[3];
    p2[0] = CGPointMake(10, 20);
    p2[1] = (CGPoint){210, 50};
    p2[2] = (CGPoint){80, 120};
    CGPathAddLines(p1, nil, p2, 3);
    // explicitly close our last added subpath
    CGPathCloseSubpath(p1);

    // draw our mutable path (with all its subpaths) filling its area
    CGContextAddPath(ctx, p1);
    CGContextSetFillColorWithColor(ctx, [[UIColor redColor] CGColor]);
    CGContextFillPath(ctx);

    // draw our mutable path (with all its subpaths) stroking its outline
    CGContextAddPath(ctx, p1);
    CGContextSetRGBStrokeColor(ctx, 0, 0, 0, 1.0);
    CGContextStrokePath(ctx);

    // display our mutable path in an image view on screen
    UIImage *i = UIGraphicsGetImageFromCurrentImageContext();
    UIImageView *iv = [[UIImageView alloc] initWithImage:i];
    [self.view addSubview:iv];
    iv.frame = self.view.frame;

    // release ressources created with the C-API of QuartzCore
    CGPathRelease(p1);
    UIGraphicsEndImageContext();

    // create a mutable copy of a path and don't use it for drawing
    CGMutablePathRef p3 = CGPathCreateMutableCopy(bp.CGPath);
    NSArray *p3points = [self pointsFromCGPath:p3];
    for (NSValue *point in p3points) {
        NSLog(@"path element in p3: %@", NSStringFromCGPoint(point.CGPointValue));
    }
    // note that UIBezierPath takes care of its path itself
    CGPathRelease(p3);

}

// modified from https://github.com/erica/iOS-6-Cookbook

#define VALUE(_INDEX_) [NSValue valueWithCGPoint:points[_INDEX_]]

void getPointsFromBezier(void *info, const CGPathElement *element)
{
    NSMutableArray *bezierPoints = (__bridge NSMutableArray *)info;

    // Retrieve the path element type and its points
    CGPathElementType type = element->type;
    CGPoint *points = element->points;

    switch (type) {
        case kCGPathElementMoveToPoint:
            NSLog(@"MoveToPoint (%3.2f, %3.2f", points->x, points->y);
            break;
        case kCGPathElementAddLineToPoint:
            NSLog(@"AddLineToPoint (%3.2f, %3.2f)", points->x, points->y);
            break;
        case kCGPathElementAddQuadCurveToPoint:
            NSLog(@"AddQuadCurveToPoint (%3.2f, %3.2f), (%3.2f, %3.2f)", points->x, points->y, points[1].x, points[1].y);
            break;
        case kCGPathElementAddCurveToPoint:
            NSLog(@"AddCurveToPoint (%3.2f, %3.2f), (%3.2f, %3.2f), (%3.2f, %3.2f)", points->x, points->y, points[1].x, points[1].y, points[2].x, points[2].y);
            break;
        case kCGPathElementCloseSubpath:
            NSLog(@"CloseSubpath (%3.2f, %3.2f)", points->x, points->y);
            break;
        default:
            NSLog(@"unknown");
            break;
    }

    // Add the points if they're available (per type)
    if (type != kCGPathElementCloseSubpath)
    {
        [bezierPoints addObject:VALUE(0)];
        if ((type != kCGPathElementAddLineToPoint) &&
            (type != kCGPathElementMoveToPoint))
            [bezierPoints addObject:VALUE(1)];
    }
    if (type == kCGPathElementAddCurveToPoint)
        [bezierPoints addObject:VALUE(2)];
}

- (NSArray *)pointsFromCGPath:(CGPathRef)path
{
    NSMutableArray *points = [NSMutableArray array];
    CGPathApply(path, (__bridge void *)points, getPointsFromBezier);
    return points;
}
于 2013-06-20T08:10:41.943 に答える