Skip to content

Instantly share code, notes, and snippets.

@ksm
Created February 14, 2012 21:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ksm/1830844 to your computer and use it in GitHub Desktop.
Save ksm/1830844 to your computer and use it in GitHub Desktop.
CoreGraphics UITableView iOS5 bevel effect function
/*
Copied and pasted from Tim Oliver's blog.
Source: http://www.tim-oliver.com/2011/10/23/creating-the-uitableview-bevel-effect-in-coregraphics/
*/
void DrawInsetBeveledRoundedRect(CGContextRef context, CGRect rect, CGFloat radius, UIColor *fillColor) {
//contract the bounds of the rectangle in to account for the stroke
CGRect drawRect = CGRectInset(rect, 1.0f, 1.0f);
//contract the height by 1 to account for the white bevel at the bottom
drawRect.size.height -= 1.0f;
//Save the current state so we don't persist anything beyond this operation
CGContextSaveGState(context);
//Generate the rounded rectangle paths
CGPathRef boxPath = [[UIBezierPath bezierPathWithRoundedRect: drawRect cornerRadius: radius] CGPath];
//For the stroke, offset by half a pixel to ensure proper drawing
CGPathRef strokePath = [[UIBezierPath bezierPathWithRoundedRect: CGRectInset(drawRect, -0.5f, -0.5f) cornerRadius: radius] CGPath];
/*Draw the bevel effect*/
CGContextSaveGState(context);
//Set the color to be slightly transparent white
CGContextSetFillColorWithColor(context, [[UIColor colorWithWhite: 1.0f alpha: 0.8f] CGColor]);
//Clip the region to only the visible portion to optimzie drawing
CGContextClipToRect(context, CGRectMake(rect.origin.x, rect.origin.y+rect.size.height-radius, rect.size.width, radius));
//draw the left corner curve
CGRect corner = CGRectMake(rect.origin.x, (rect.origin.y+rect.size.height)-(2*radius)-1, (radius*2)+1, (radius*2)+1);
CGContextFillEllipseInRect(context, corner);
//draw the right corner
corner.origin.x = rect.origin.x + rect.size.width - (radius*2)-1;
CGContextFillEllipseInRect(context, corner);
//draw the rectangle in the middle
//set the blend mode to replace any existing pixels (or else we'll see visible overlap)
CGContextSetBlendMode(context, kCGBlendModeCopy);
CGContextFillRect(context, CGRectMake(rect.origin.x+radius, rect.origin.y+rect.size.height-radius, rect.size.width-(2*radius),radius+1));
CGContextRestoreGState(context);
/*Draw the main region */
CGContextSaveGState(context);
//fill it with our colour of choice
CGContextSetFillColorWithColor(context, [fillColor CGColor]);
//use the stroke path so the boundaries line up with the stroke (else we'll see a gap on retina devices)
CGContextAddPath(context, strokePath);
//fill it
CGContextFillPath(context);
CGContextRestoreGState(context);
/*Main fill region inner drop shadow*/
/*(This is done by duplicating the path, offsetting the duplicate by 1 pixel, and using the EO winding fill rule to fill the gap between the two)*/
CGContextSaveGState(context);
//set the colour to be a VERY faint grey
CGContextSetFillColorWithColor(context, [[UIColor colorWithWhite: 0.0f alpha: 0.08f] CGColor]);
//clip the shadow to the top of the box (to reduce overhead)
CGContextClipToRect(context, CGRectMake( drawRect.origin.x, drawRect.origin.y, drawRect.size.width, radius ));
//add the first instance of the path
CGContextAddPath(context, boxPath);
//translate the draw origin down by 1 pixel
CGContextTranslateCTM(context, 0.0f, 1.0f);
//add the second instance of the path
CGContextAddPath(context, boxPath);
//use the EO winding rule to fill the gap between the two paths
CGContextEOFillPath(context);
CGContextRestoreGState(context);
/*Outer Stroke*/
/*This is drawn outside of the fill region to prevent the fill region bleeding over in some cases*/
CGContextSaveGState(context);
//set the line width to be 1 pixel
CGContextSetLineWidth(context, 1.0f);
//set the the colour to be a very transparent shade of grey
CGContextSetStrokeColorWithColor(context, [[UIColor colorWithWhite: 0.0f alpha: 0.18f] CGColor]);
//set up the path to draw the stroke along
CGContextAddPath(context, strokePath);
//set the blending mode to replace underlying pixels on this layer (so the background will come through through)
CGContextSetBlendMode(context, kCGBlendModeCopy);
//draw the path
CGContextStrokePath(context);
CGContextRestoreGState(context);
//Restore the previous CG state
CGContextRestoreGState(context);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment