views:

311

answers:

1

Hi!

I'm trying to create a custom UIButton that should look like a UIButtonTypeRoundedRect. In my drawRect:, I'm creating a path with first one call to CGContextMoveToPoint() and then four calls to CGContextAddArc(). I then stroke the path. However, in the resulting image the four rounded corners are clearly thicker than the rest of the path.

I suspected this had something to do with anti-aliasing, so I tried switching it off with CGContextSetShouldAntiAlias(), but then it looked even worse. I've also tried experimenting with the line width, but the arcs are always thicker than the straight lines. Apple's UIButtonTypeRoundedRect looks perfectly fine, so it must be possible to solve somehow. Does anybody have a clue?

Edit: the relevant code:

CGContextRef context = UIGraphicsGetCurrentContext();
CGContextBeginPath(context);

CGContextMoveToPoint(context, rect.origin.x + kRoundedRectButtonRadius, rect.origin.y);
CGContextAddArc(context, rect.origin.x + rect.size.width - kRoundedRectButtonRadius, rect.origin.y + kRoundedRectButtonRadius, kRoundedRectButtonRadius, 3 * M_PI_2, 0, NO);
CGContextAddArc(context, rect.origin.x + rect.size.width - kRoundedRectButtonRadius, rect.origin.y + rect.size.height - kRoundedRectButtonRadius, kRoundedRectButtonRadius, 0, M_PI_2, NO);
CGContextAddArc(context, rect.origin.x + kRoundedRectButtonRadius, rect.origin.y + rect.size.height - kRoundedRectButtonRadius, kRoundedRectButtonRadius, M_PI_2, M_PI, NO);
CGContextAddArc(context, rect.origin.x + kRoundedRectButtonRadius, rect.origin.y + kRoundedRectButtonRadius, kRoundedRectButtonRadius, M_PI, 3 * M_PI_2, NO);

CGContextClosePath(context);
CGContextSetLineWidth(context, 1.7);
CGContextStrokePath(context);
+6  A: 

I've run into this before with drawing custom buttons. The behaviour you are seeing stems from the fact that cocoa's drawing routines draw lines centered around the pixel positions on which you ask them to. Let me explain.

The straight lines that you are drawing fall on the very edge of the button's rectangle. When your drawing routine is called, Cocoa has conveniently set the clipping region to the exact boundary of the button rectangle, but when you ask Cocoa to draw a line along the edge, exactly half of the line is drawn outside of the clipping rectangle.

You notice the difference in the rounded corners because the curved portion falls completely inside the clipping rectangle, so none of it is clipped away.

Now for the solution:

Let's assume that the lines you are drawing are exactly two pixels thick. This would mean that one pixel is drawn inside the clipping rectangle, and one is drawn outside (and is therefore ignored). All you have to do is draw your lines one pixel closer to the center of the rectangle. In the case of a custom drawing routine, you are probably using:

NSRect myBounds = [self bounds];

And then computing your corner points from there. Insead, use:

NSRect myProperBounds = NSInsetRect([self bounds], 1.0, 1.0);

And you should be good to go.

e.James
You are a genius, my friend - and I should be thee forever grateful!
eliego
I'm no genius, I've just been there before. Have fun with the coding :)
e.James
My savior! Thank you so much!
DenNukem