39

A lot of apps pop up a transparent view with rounded corners and an activityIndicator when running a time consuming operation.

How is this rounding done and is it possible to do it just using Interface Builder (as there are lots of places I'd like to use something like this)? Or, should I use an imageview with a rounded rect or stretchable image? Do I need to draw the background myself?

So far, I have managed to get a basic view with similar transparency by setting the alphaValue in Interface Builder however it doesn't have rounded corners, and also the transparency seems to apply to all subviews (I don't want the text and activityindicator to be transparent, however even though I set the alphaValue on those in IB it seems to get ignored).

frankodwyer
  • 13,948
  • 9
  • 50
  • 70

5 Answers5

78

As of iPhone SDK 3.0, you can simply use the layer's cornerRadius property. E.g.:

view.layer.cornerRadius = 10.0;

Along the same lines, you can change the view's border color and width:

view.layer.borderColor = [[UIColor grayColor] CGColor];
view.layer.borderWidth = 1;
Mirko Froehlich
  • 12,006
  • 4
  • 27
  • 23
  • any idea how I can get a margin between the border and the content in the UILabel? – dlinsin Jan 15 '10 at 16:12
  • I'm not aware of any way to do that. With a UIButton, you should be able to use the contentEdgeInsets property, but UILabel doesn't seem to have anything like that. Perhaps just create a UIView with border and rounded corners, then add your UILabel as a subview, slightly inset. – Mirko Froehlich Jan 15 '10 at 21:38
  • 11
    You may need to `#import ` if you get an error trying to access the `layer` property. Otherwise, this is a great alternative to manually drawing the rounded corners, and by not having to implement a custom `drawRect:`, it works for simple container views. – Steve Madsen Mar 11 '10 at 17:45
  • 4
    You might also have to add: view.layer.masksToBounds = YES; if your image extends beyond the corner radius. – Ward Mar 25 '10 at 02:11
47
view.layer.cornerRadius = radius;

The hard way (that used to be required in the first iPhone SDK) is to create your own UIView subclass with drawRect: method:

 CGContextRef context = UIGraphicsGetCurrentContext();
 CGContextSetRGBFillColor(context, 0,0,0,0.75);

 CGContextMoveToPoint(context, rect.origin.x, rect.origin.y + radius);
 CGContextAddLineToPoint(context, rect.origin.x, rect.origin.y + rect.size.height - radius);
 CGContextAddArc(context, rect.origin.x + radius, rect.origin.y + rect.size.height - radius, 
                radius, M_PI, M_PI / 2, 1); //STS fixed
 CGContextAddLineToPoint(context, rect.origin.x + rect.size.width - radius, 
                        rect.origin.y + rect.size.height);
 CGContextAddArc(context, rect.origin.x + rect.size.width - radius, 
                rect.origin.y + rect.size.height - radius, radius, M_PI / 2, 0.0f, 1);
 CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, rect.origin.y + radius);
 CGContextAddArc(context, rect.origin.x + rect.size.width - radius, rect.origin.y + radius, 
                radius, 0.0f, -M_PI / 2, 1);
 CGContextAddLineToPoint(context, rect.origin.x + radius, rect.origin.y);
 CGContextAddArc(context, rect.origin.x + radius, rect.origin.y + radius, radius, 
                -M_PI / 2, M_PI, 1);

 CGContextFillPath(context);

Note: rect in this code should be taken from [self bounds] (or whatever location you want it in), it won't make sense with rect passed to drawRect: method.

Kornel
  • 97,764
  • 37
  • 219
  • 309
  • Do I still set transparency and bg color etc through IB and how do I stop the alpha applying to the subviews (text/activityIndicator)? At least I think that is what happens - both the text and the spinner look very anemeic/grey, like the background is coming through the white text. – frankodwyer Jun 23 '09 at 11:26
  • Set transparent background in IB, and use semitransparent fill color in the code. I've updated the answer. – Kornel Jun 23 '09 at 11:28
  • works great. one minor point it is missing the 'float radius=0.5f;' that it needs to compile (oddly enough I also left out 'rect=self.bounds and it still worked) – frankodwyer Jun 23 '09 at 21:14
8

I abstracted out @lostInTransit's response into this function:

static void ContextAddRoundedRect(CGContextRef c, CGRect rect, CGFloat radius) {
  CGFloat minX = CGRectGetMinX(rect);
  CGFloat maxX = CGRectGetMaxX(rect);
  CGFloat minY = CGRectGetMinY(rect);
  CGFloat maxY = CGRectGetMaxY(rect);

  CGContextMoveToPoint(c, minX + radius, minY);
  CGContextAddArcToPoint(c, maxX, minY, maxX, minY + radius, radius);
  CGContextAddArcToPoint(c, maxX, maxY, maxX - radius, maxY, radius);
  CGContextAddArcToPoint(c, minX, maxY, minX, maxY - radius, radius);
  CGContextAddArcToPoint(c, minX, minY, minX + radius, minY, radius);
}

which places the path onto the context for you to do with as you may

slightly different CoreGraphics calls and i didn't close the path, in case you want to add that

CGContextFillPath(c);
bshirley
  • 8,217
  • 1
  • 37
  • 43
  • +1. Just for my notes, close the path using `CGContextFillPath(c);` or `CGContextStrokePath(c)`. You can put these in a calling function and then call `ContextAddRoundedRect` twice to get outline and fill. Something like this `static void ContextAddRoundedRectWithOutline(CGContextRef c, CGRect rect, CGFloat radius, UIColor* outline, UIColor* fill)` – Dan Rosenstark Apr 09 '12 at 17:12
7

In your view do this in the drawRect method

float radius = 5.0f;

CGRect rect = self.bounds;
CGContextRef context = UIGraphicsGetCurrentContext();   
rect = CGRectInset(rect, 1.0f, 1.0f);

CGContextBeginPath(context);
CGContextSetGrayFillColor(context, 0.5, 0.7);
CGContextMoveToPoint(context, CGRectGetMinX(rect) + radius, CGRectGetMinY(rect));
CGContextAddArc(context, CGRectGetMaxX(rect) - radius, CGRectGetMinY(rect) + radius, radius, 3 * M_PI / 2, 0, 0);
CGContextAddArc(context, CGRectGetMaxX(rect) - radius, CGRectGetMaxY(rect) - radius, radius, 0, M_PI / 2, 0);
CGContextAddArc(context, CGRectGetMinX(rect) + radius, CGRectGetMaxY(rect) - radius, radius, M_PI / 2, M_PI, 0);
CGContextAddArc(context, CGRectGetMinX(rect) + radius, CGRectGetMinY(rect) + radius, radius, M_PI, 3 * M_PI / 2, 0);

CGContextClosePath(context);
CGContextFillPath(context);

This will make your rounded rectangle for your view. You can find a complete example in the HeadsUpUI sample provided with the SDK. HTH

lostInTransit
  • 70,519
  • 61
  • 198
  • 274
6

MBProgressHUD....
http://www.cocoadev.com/index.pl?MBProgressHUD

casey
  • 1,118
  • 1
  • 13
  • 25