Search code examples
objective-cuiimageuislider

The rounded pure color image created by code is blur


In objective-c, I make a circle shape programmatically by following codes:

+(UIImage *)makeRoundedImage:(CGSize) size backgroundColor:(UIColor *) backgroundColor cornerRadius:(int) cornerRadius
{
    UIImage* bgImage = [self imageWithColor:backgroundColor andSize:size];;

    CALayer *imageLayer = [CALayer layer];
    imageLayer.frame = CGRectMake(0, 0, size.width, size.height);
    imageLayer.contents = (id) bgImage.CGImage;

    imageLayer.masksToBounds = YES;
    imageLayer.cornerRadius = cornerRadius;

    UIGraphicsBeginImageContext(bgImage.size);
    [imageLayer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *roundedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return roundedImage;
}

The imageWithColor method is as following:

+(UIImage *)imageWithColor:(UIColor *)color andSize:(CGSize)size
{
    //quick fix, or pop up  CG invalid context 0x0 bug
    if(size.width == 0) size.width = 1;
    if(size.height == 0) size.height = 1;
    //---quick fix

    UIImage *img = nil;

    CGRect rect = CGRectMake(0, 0, size.width, size.height);
    UIGraphicsBeginImageContext(rect.size);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(context,
                                   color.CGColor);
    CGContextFillRect(context, rect);
    img = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return img;
}

Then I used it to create a pure color circle shape image, but what I found is the circle image is not perfect rounded. As an example, please see following code:

CGSize size = CGSizeMake(diameter, diameter);
int r = ceil((float)diameter/2.0);
UIImage *imageNormal = [self makeRoundedImage:size backgroundColor:backgroundColor cornerRadius:r];
[slider setThumbImage:imageNormal forState:UIControlStateNormal];

First I created a circle image, then I set the image as the thumb to a UISlider. But what shown is as the picture shown below:

enter image description here

You can see the circle is not an exact circle. I'm thinking probably it caused by the screen resolution issue? Because if I use an image resource for the thumb, I need add @2x. Anybody know the reason? Thanx in advance.


updated on 8th Aug 2015.

Further to this question and the answer from @Noah Witherspoon, I found the blurry edge issue has been solved. But still, the circle looks like being cut. I used the code as following:

CGRect rect = CGRectMake(0.0f, 0.0f, radius*2.0f, radius*2.0f);
UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0.0);     
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, color.CGColor);
CGContextFillEllipseInRect(context, rect);
UIImage* image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;

And the circle looks like:

enter image description here

You can see the edge has been cut.

I changed the code as following:

CGRect rect = CGRectMake(0.0f, 0.0f, radius*2.0f+4, radius*2.0f+4);
CGRect rectmin = CGRectMake(2.0f, 2.0f, radius*2, radius*2);
UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0.0);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, color.CGColor);
CGContextFillEllipseInRect(context, rectmin);
UIImage* image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;

You can see the circle looks better(The top edge and the bottom edge):

enter image description here

I made the fill rect size smaller, and the edge looks better, but I don't think it's a nice solution. Still, does anybody know why this happen?


Solution

  • From your screenshot it looks like you do actually have a circular image, but its scale is wrong—it’s not Retina—so it looks blurry and not-circular. The key thing is that instead of using UIGraphicsBeginImageContext which defaults to a scale of 1.0 (as compared to your screen, which is at a scale of 2.0 or 3.0), you should be using UIGraphicsBeginImageContextWithOptions. Also, you don’t need to make a layer or a view to draw a circle in an image context.

    + (UIImage *)makeCircleImageWithDiameter:(CGFloat)diameter color:(UIColor *)color {
        UIGraphicsBeginImageContextWithOptions(CGSizeMake(diameter, diameter), NO, 0 /* scale (0 means “use the current screen’s scale”) */);
        [color setFill];
        CGContextFillEllipseInRect(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, diameter, diameter));
        UIImage *image = UIGraphicsGetImageFromCurrentContext();
        UIGraphicsEndImageContext();
        return image;
    }