Is it possible to get all uibezerpath from uiview?

 ̄綄美尐妖づ 提交于 2019-12-13 19:36:29

问题


I've been researching and found no answer.

Is it possible to get all UIBezierPath from UIView once drawn in UIView if I use CGGontext for drawing it to the view? (if yes, can you give me an idea to how?) The UIBezierPath came from user input, so if the user draws a lot of UIBezierPath, I need all those path and save it to a .svg file.


回答1:


Here's a better working example, after testing some of the answers I've given in my commments, this is the one that will return an array of shapelayers, or layers depending on what you are looking for:

CAShapeLayer * firstNameCorners = [CAShapeLayer layer];
[firstNameCorners setPath:[UIBezierPath bezierPathWithRoundedRect:CGRectMake(100, 100, 196.75, 44.0) byRoundingCorners:UIRectCornerBottomLeft|UIRectCornerTopLeft cornerRadii:(CGSize){2.5, 2.5}].CGPath];
[[self.view layer] addSublayer:firstNameCorners];

NSMutableArray *this = [[NSMutableArray alloc] init];

for (CALayer * rd in self.view.layer.sublayers) {
    if ([rd isKindOfClass:[CAShapeLayer class]]) {
        [this addObject:rd];
        NSLog(@"this is a layer: %@", rd);
    }
}
NSLog(@"this is an Array of Shapes: %@", this);

CAShapeLayer can also store just a single line, doesn't matter how complex the line is, this object can store it if it's coming from a UIBezierPath and you store this in the subLayers of the UIView you are drawing on. And in fact to expand this further, and for your purposes see the following, this will return the CGPath which, according to your question, is what you wanted:

CAShapeLayer * firstNameCorners = [CAShapeLayer layer];
[firstNameCorners setPath:[UIBezierPath bezierPathWithRoundedRect:CGRectMake(100, 100, 96.75, 44.0) byRoundingCorners:UIRectCornerBottomLeft|UIRectCornerTopLeft cornerRadii:(CGSize){2.5, 2.5}].CGPath];
[[self.view layer] addSublayer:firstNameCorners];

NSMutableArray *this = [[NSMutableArray alloc] init];

for (CALayer * rd in self.view.layer.sublayers) {
    if ([rd isKindOfClass:[CAShapeLayer class]]) {
        [this addObject:rd];
        CAShapeLayer * rf = (CAShapeLayer*)rd;
        NSLog(@"this is a layer: %@", rf.path);
        CGRect pathBounds = CGPathGetBoundingBox(rf.path);
        NSLog(@"this is this boundingBox: origin.X: %f, origin.X: %f, size.Width: %f, size.Height: %f", pathBounds.origin.x, pathBounds.origin.y, pathBounds.size.width, pathBounds.size.height);
    }
}
NSLog(@"this is an Array of Shapes: %@", this);

And, if you want to go even further, then this works to store the CGRect coordinates, and also, this will show you how to retrive and use these coordinates:

CAShapeLayer * firstNameCorners = [CAShapeLayer layer];
[firstNameCorners setPath:[UIBezierPath bezierPathWithRoundedRect:CGRectMake(100, 100, 196.75, 44.0) byRoundingCorners:UIRectCornerBottomLeft|UIRectCornerTopLeft cornerRadii:(CGSize){2.5, 2.5}].CGPath];
[[self.view layer] addSublayer:firstNameCorners];

NSMutableArray *this = [[NSMutableArray alloc] init];

NSMutableArray *that = [[NSMutableArray alloc] init];

for (CALayer * rd in self.view.layer.sublayers) {
    if ([rd isKindOfClass:[CAShapeLayer class]]) {
        [this addObject:rd];
        CAShapeLayer * rf = (CAShapeLayer*)rd;
        NSLog(@"this is a layer: %@", rf.path);
        CGRect pathBounds = CGPathGetBoundingBox(rf.path);
        [that addObject:[NSValue valueWithCGRect:pathBounds]];
        NSLog(@"this is this boundingBox: origin.X: %f, origin.X: %f, size.Width: %f, size.Height: %f", pathBounds.origin.x, pathBounds.origin.y, pathBounds.size.width, pathBounds.size.height);
    }
}

Now, to finish off, and this is an adaptation from https://github.com/erica/iOS-6-Cookbook, and this is to show the complete unraveling of my drawing of a UIBezierPath to begin with:

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

-(void)showPaths
{
    CAShapeLayer * firstNameCorners = [CAShapeLayer layer];
    [firstNameCorners setPath:[UIBezierPath bezierPathWithRoundedRect:CGRectMake(100, 100, 196.75, 44.0) byRoundingCorners:UIRectCornerBottomLeft|UIRectCornerTopLeft cornerRadii:(CGSize){2.5, 2.5}].CGPath];
    [[self.view layer] addSublayer:firstNameCorners];

    NSMutableArray *this = [[NSMutableArray alloc] init];

    NSMutableArray *that = [[NSMutableArray alloc] init];

    for (CALayer * rd in self.view.layer.sublayers) {
        if ([rd isKindOfClass:[CAShapeLayer class]]) {
            [this addObject:rd];
            CAShapeLayer * rf = (CAShapeLayer*)rd;
            NSLog(@"this is a layer: %@", rf.path);
            CGRect pathBounds = CGPathGetBoundingBox(rf.path);
            [that addObject:[NSValue valueWithCGRect:pathBounds]];

            CGMutablePathRef p3 = CGPathCreateMutableCopy(rf.path);
            NSArray *p3points = [self pointsFromCGPath:p3];
            for (NSValue *point in p3points) {
                NSLog(@"path element in p3: %@", NSStringFromCGPoint(point.CGPointValue));
            }
            NSLog(@"this is this boundingBox: origin.X: %f, origin.X: %f, size.Width: %f, size.Height: %f", pathBounds.origin.x, pathBounds.origin.y, pathBounds.size.width, pathBounds.size.height);
        }
    }
}

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;
}

The output will log to the console, all the paths that are stored in CAShapeLayer we started with, the out put is too big and messy to post here, but here's what the start of it looks like:

[30146:2680987] MoveToPoint (103.82, 100.00

[30146:2680987] AddLineToPoint (296.75, 100.00)

[30146:2680987] AddLineToPoint (296.75, 144.00)

[30146:2680987] AddLineToPoint (103.82, 144.00)

[30146:2680987] AddCurveToPoint (102.72, 144.00), (102.17, 144.00), (101.67, 143.84)

[30146:2680987] AddLineToPoint (101.58, 143.81)

[30146:2680987] AddCurveToPoint (100.93, 143.58), (100.42, 143.07), (100.19, 142.42)

[30146:2680987] AddCurveToPoint (100.00, 141.83), (100.00, 141.28), (100.00, 140.18)

[30146:2680987] AddLineToPoint (100.00, 103.82)

[30146:2680987] AddCurveToPoint (100.00, 102.72), (100.00, 102.17), (100.16, 101.67)

[30146:2680987] AddLineToPoint (100.19, 101.58)

[30146:2680987] AddCurveToPoint (100.42, 100.93), (100.93, 100.42), (101.58, 100.19)

[30146:2680987] AddCurveToPoint (102.17, 100.00), (102.72, 100.00), (103.82, 100.00)

[30146:2680987] AddLineToPoint (103.82, 100.00)

[30146:2680987] path element in p3: {103.8216625, 100}

[30146:2680987] path element in p3: {296.75, 100}

[30146:2680987] path element in p3: {296.75, 144}

[30146:2680987] path element in p3: {103.8216625, 144}

[30146:2680987] path element in p3: {102.72123239404632, 144}

[30146:2680987] path element in p3: {102.17101736015751, 144}




回答2:


If you're using Core Graphics to draw the paths, you probably have some model backing the view that drawRect avails upon in order to draw all the paths. If you don't (i.e. you're just updating a bitmap), you should simply refactor that code to capture and save the information necessary to represent the paths.



来源:https://stackoverflow.com/questions/32108808/is-it-possible-to-get-all-uibezerpath-from-uiview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!