简体   繁体   中英

How to draw image inside a circular bezier path

I am trying to create a custom view to draw a music CD with the album artwork on the CD.

Currently I use core graphics to draw two circular disks inside the drawRect method. The inner disk's colour is set to the background colour of the view to make it look like the inner circle is a hollow circle.

My problem is that I can't draw the UIImage inside the the circular bezier path to get the result that I need.

Here's my drawRect code:

// Draw a CD like view using three drawing operations:
// 1st draw the main disk
// 2nd draw the image if it is set
// 3rd draw the inner disk over the image so that it looks like it is a hollow disk with the image painted on the disk.
// Note:) This view expects its aspect ratio to be set as 1:1
- (void)drawRect:(CGRect)rect
{
    // Draw the main Circular CD disk
    UIBezierPath* outerRing = [UIBezierPath bezierPathWithOvalInRect:self.bounds];

    [self.mainColor setFill];
    [outerRing fill];

    [self.outerRingColor setStroke];
    [outerRing stroke];

    // Draw the album image if it is set
    if(self.artwork){
        [self.artwork drawInRect:self.bounds blendMode:kCGBlendModeNormal alpha:1.0];
    }

    // now draw another smaller disk inside
    // this will be a percentage smaller than the whole disk's bounds and will be centered inside it
    CGFloat sidePaddingCoord = ((1.0f - INNER_DISK_SIZE_PERCENTAGE) / 2) * self.bounds.size.height;
    CGFloat side = INNER_DISK_SIZE_PERCENTAGE * self.bounds.size.width;

    UIBezierPath* innerRing = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(sidePaddingCoord, sidePaddingCoord, side, side)];

    [self.innerRingColor setFill];
    [innerRing fill];

    [innerRing stroke];
}

This fills the image as a square. I want the image to be clipped inside the outerRing bezier path so that it looks like a music CD.

I'm sure there is a way to use core graphics to achieve something else besides using the image's drawInRect method. Is there any way to 'clip' the image inside the circular bezier path or only draw inside the bezier path?

I've read really great posts by rob mayoff, UIBezierPath Subtract Path , iOS UIImage clip to paths , many thanks.

Here is an adoption of his code. Keep your creation code of outerRing and innerRing , add them to an array named paths .

[self.paths addObject:outerRing];
[self.paths addObject:innerRing];

Then use this help method.

- (UIImage *)maskedImage
{
    CGRect rect = CGRectZero;
    rect.size = self.originalImage.size;
    UIGraphicsBeginImageContextWithOptions(rect.size, YES, 0.0);

    UIBezierPath *clipPath = [UIBezierPath bezierPathWithRect:CGRectInfinite];
    [clipPath appendPath:self.paths[1]];
    clipPath.usesEvenOddFillRule = YES;

    CGContextSaveGState(UIGraphicsGetCurrentContext()); {
        [clipPath addClip];
        [[UIColor orangeColor] setFill];
        [self.paths[0] fill];
    } CGContextRestoreGState(UIGraphicsGetCurrentContext());

    UIImage *mask = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0.0); {
        CGContextClipToMask(UIGraphicsGetCurrentContext(), rect, mask.CGImage);
        [self.originalImage drawAtPoint:CGPointZero];
    }
    UIImage *maskedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return maskedImage;
}

In drawRect ,

UIImage *maskedImage = [self maskedImage];
[maskedImage drawInRect:self.bounds blendMode:kCGBlendModeNormal alpha:1.0];

Try below code:

    UIImageView *userImageView= [[UIImageView alloc] initWithFrame:CGRectMake(85, 55.0, 90, 90)];
    userImageView.layer.cornerRadius = 90/2;
    userImageView.clipsToBounds = YES;
    userImageView.layer.borderWidth = 1.0f;
    userImageView.layer.borderColor = [UIColor blueColor];
    [self.view addSubview:userImageView]; //or add it to the view you want
    UIImage *userImage = [UIImage imageNamed:@"<image you want to set>"];
    userImageView= [[UIImageView alloc] initWithFrame:CGRectMake(90, 60.0, 80, 80)];
    userImageView.image = userImage;
    userImageView.layer.cornerRadius = 80/2;
    userImageView.clipsToBounds = YES;
    userImageView.layer.borderWidth = 1.0f;
    userImageView.layer.borderColor = [UIColor blueColor;
    [self.view addSubview:userImageView]; //or add it to the view you want

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM