In my iPad app, I want a second view to appear within the main when the user clicks a button. The new view will be smaller than the first, and darken the background when it is displayed. I want the top two corners of the new view to appear rounded, but using cornerRadius sets all of them rounded. How can I make just two corners rounded?
You have to do this in drawRect:. I actually modified the classic addRoundedRectToPath: so that it takes a bitmap and rounds the corners you request:
static void addRoundedRectToPath(CGContextRef context, CGRect rect, float radius, UIImageRoundedCorner cornerMask)
{
CGContextMoveToPoint(context, rect.origin.x, rect.origin.y + radius);
CGContextAddLineToPoint(context, rect.origin.x, rect.origin.y + rect.size.height - radius);
if (cornerMask & UIImageRoundedCornerTopLeft) {
CGContextAddArc(context, rect.origin.x + radius, rect.origin.y + rect.size.height - radius,
radius, M_PI, M_PI / 2, 1);
}
else {
CGContextAddLineToPoint(context, rect.origin.x, rect.origin.y + rect.size.height);
CGContextAddLineToPoint(context, rect.origin.x + radius, rect.origin.y + rect.size.height);
}
CGContextAddLineToPoint(context, rect.origin.x + rect.size.width - radius,
rect.origin.y + rect.size.height);
if (cornerMask & UIImageRoundedCornerTopRight) {
CGContextAddArc(context, rect.origin.x + rect.size.width - radius,
rect.origin.y + rect.size.height - radius, radius, M_PI / 2, 0.0f, 1);
}
else {
CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, rect.origin.y + rect.size.height);
CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, rect.origin.y + rect.size.height - radius);
}
CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, rect.origin.y + radius);
if (cornerMask & UIImageRoundedCornerBottomRight) {
CGContextAddArc(context, rect.origin.x + rect.size.width - radius, rect.origin.y + radius,
radius, 0.0f, -M_PI / 2, 1);
}
else {
CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, rect.origin.y);
CGContextAddLineToPoint(context, rect.origin.x + rect.size.width - radius, rect.origin.y);
}
CGContextAddLineToPoint(context, rect.origin.x + radius, rect.origin.y);
if (cornerMask & UIImageRoundedCornerBottomLeft) {
CGContextAddArc(context, rect.origin.x + radius, rect.origin.y + radius, radius,
-M_PI / 2, M_PI, 1);
}
else {
CGContextAddLineToPoint(context, rect.origin.x, rect.origin.y);
CGContextAddLineToPoint(context, rect.origin.x, rect.origin.y + radius);
}
CGContextClosePath(context);
}
This takes a bitmask (I called it UIImageRoundedCorner because I was doing this for images, but you can call it whatever) and then builds up a path based on the corners you want rounded. Then you apply that path to the view in drawRect:
CGContextBeginPath(context);
addRoundedRectToPath(context, rect, radius, yourMask);
CGContextClosePath(context);
CGContextClip(context);
As I said, I was doing this for UIImages, so my code isn't exactly set up for use in drawRect:, but it should be pretty easy to adapt it. You're basically just building up a path and then clipping the context to it.
Edit: To explain the bitmask part, it's just an enum:
typedef enum {
UIImageRoundedCornerTopLeft = 1,
UIImageRoundedCornerTopRight = 1 << 1,
UIImageRoundedCornerBottomRight = 1 << 2,
UIImageRoundedCornerBottomLeft = 1 << 3
} UIImageRoundedCorner;
In this way you can OR things together to form a bitmask that identifies corners, since each member of the enum represents a different power of two in the bitmask.
Much Later Edit:
I've discovered an easier way to do this using UIBezierPath
's bezierPathWithRoundedRect:byRoundingCorners:cornerRadii:
. Just use the bezier path object's CGPath
in your context.