iOS:获取 CGMutablePath 不在 drawRect 中:并将其分配给 CAShapeLayer 的路径
Posted
技术标签:
【中文标题】iOS:获取 CGMutablePath 不在 drawRect 中:并将其分配给 CAShapeLayer 的路径【英文标题】:iOS: Getting CGMutablePath not in drawRect: and Assign it to CAShapeLayer's Path 【发布时间】:2013-06-15 21:31:04 【问题描述】:我已经为此苦苦思索了好几个小时。我试着阅读并寻找答案。我什至尝试过“走开,然后再回来”的方法,但没有奏效。我什至尝试过瑜伽和冥想!我没有占上风。。
所以请各位高手赐教。
我只是想获取不在 drawRect 内的 CGPath 的副本:
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, ......);
CGPathAddLineToPoint(path, ....);
CGPathAddLineToPoint(path, ....);
CGPathAddLineToPoint(path, ....);
CGPathAddLineToPoint(path, ....);
最后:
CGPathCloseSubpath(path);
CGContextAddPath(context, path);
那没有用,所以我也尝试使用而不是上面的 2 个调用:
CGPathCreateMutableCopy(path);
最终 - 我只是希望能够获取此路径并将其作为路径插入 CAShapeLayer 并通过进行此调用为其设置动画:
animation.toValue = [UIBezierPath bezierPathWithCGPath:path];
因此,在我尝试进行另一项放松活动(例如不带降落伞的跳伞)以理清思路并最终做到这一点之前,您能帮我举几个例子吗?除此之外,您能否详细解释一下使用以下函数的正确方法:
CGPathCloseSubpath(path);
CGContextAddPath(context, path);
CGPathCreateMutableCopy(path);
提前致谢。
【问题讨论】:
我不确定你想在这里做什么。你想要一个返回 CGMutablePath 的方法吗? @Inafziger:嗨,我只是想创建 CGPath。但是从 Apple 的文档和 *** 上的文字来看,上述函数都不能在 drawRect: 之外调用。而不是依赖于系统调用 setNeedsDisplay: 依次调用 drawRect: 我希望能够在 drawRect: 之外的其他地方获取路径,但是如果我在 drawRect: 之外调用上述内容,我会得到一个 nil 0x0 上下文例外。谢谢。 【参考方案1】:CGPath 是具有 C 风格 API 的 C 风格数据结构。基本上它是组成路径的点列表。
CGContext 也是一种用于绘制图像的 C 风格数据结构(可能大一点),即将点转换为彩色像素。
我将我的 sn-ps 放入一个函数中,您可以简单地将其复制并粘贴到单个屏幕 xcode 项目中。您会在代码中找到解释为 cmets 的解释,以及用于深入调试和探索 CGPath 对象的两个函数(我从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;
【讨论】:
以上是关于iOS:获取 CGMutablePath 不在 drawRect 中:并将其分配给 CAShapeLayer 的路径的主要内容,如果未能解决你的问题,请参考以下文章