want to "avoid" animation effects of UIView subclass - iphone

I want to create "rounded" "semi-transparent" UIView (or anything does similar)
my code below results in animation effects, gradually change transparent density.
What I want is to avoid this effects and draw the resulting image straight from the beginning.
Can anyone know how to do?
Thank you.
- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame])
{
// Initialization code
super.opaque = NO;
self.alpha = 1.0f;
self.strokeColor = kDefaultStrokeColor;
super.backgroundColor = [UIColor clearColor];
self.rectColor = kDefaultRectColor;
self.strokeWidth = kDefaultStrokeWidth;
self.cornerRadius = kDefaultCornerRadius;
self.contentMode = UIViewContentModeRedraw;
self.clearsContextBeforeDrawing = NO;
}
return self;
}
- (void)setBackgroundColor:(UIColor *)newBGColor
{
// Ignore attempt to set backgroundColor
}
- (void)setOpaque:(BOOL)newIsOpaque
{
// Ignore attempt to set opaque to YES.
}
- (void)drawRect:(CGRect)rect {
BOOL areEnabled = [UIView areAnimationsEnabled];
// with or without setAnimationsEnabled:NO gives me the same result
[UIView setAnimationsEnabled:NO];
// with or without beginAnimations and commitAnimations gives me the same result
[UIView beginAnimations:#"test" context:nil];
[UIView setAnimationRepeatCount:1];
// [UIView setAnimationBeginsFromCurrentState:YES];
// With or without setAnimationDelay gives me the same result
//[UIView setAnimationDelay:0.0f];
// With or without setAnimationDuration gives me the same result
// passing 0.0f the same
//[UIView setAnimationDuration:0.1f];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextBeginPath(context);
CGContextSetLineWidth(context, strokeWidth);
CGContextSetStrokeColorWithColor(context, self.strokeColor.CGColor);
CGContextSetFillColorWithColor(context, self.rectColor.CGColor);
CGRect rrect = self.bounds;
CGFloat radius = cornerRadius;
CGFloat width = CGRectGetWidth(rrect);
CGFloat height = CGRectGetHeight(rrect);
// Make sure corner radius isn't larger than half the shorter side
if (radius > width/2.0)
radius = width/2.0;
if (radius > height/2.0)
radius = height/2.0;
CGFloat minx = CGRectGetMinX(rrect);
CGFloat midx = CGRectGetMidX(rrect);
CGFloat maxx = CGRectGetMaxX(rrect);
CGFloat miny = CGRectGetMinY(rrect);
CGFloat midy = CGRectGetMidY(rrect);
CGFloat maxy = CGRectGetMaxY(rrect);
CGContextMoveToPoint(context, minx, midy);
CGContextAddArcToPoint(context, minx, miny, midx, miny, radius);
CGContextAddArcToPoint(context, maxx, miny, maxx, midy, radius);
CGContextAddArcToPoint(context, maxx, maxy, midx, maxy, radius);
CGContextAddArcToPoint(context, minx, maxy, minx, midy, radius);
CGContextClosePath(context);
CGContextDrawPath(context, kCGPathFillStroke);
CGContextClip(context);
[UIView commitAnimations];
[UIView setAnimationsEnabled:areEnabled];
// I am stacked...
}

Here's how I've done it in a Cocoa Touch application that I've been working on:
[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
// Change opacity (or whatever) here.
[CATransaction commit];
Not sure if this is the best way to do it (or if it'll even work outside the iPhone environment), as I'm a bit of a Cocoa novice myself. Could be worth a try, though.

Using UIView animations from within drawRect is pointless. Also, it's not possible to disable animations by overwriting UIView properties since CoreAnimation animates layer—not view—properties. If the alpha fades when using one of you views, the problem is not in your classe's implementation, but from where it is called. Some surrounding code did [UIView beginAnimations] before setting your view's or superview's alpha.
Do disable all animations, you can use the method proposed by David.

As of 3.0, you can have any view round corners easily:
1) Set clipsToBounds to YES.
2) set view.layer.cornerRadius to some value (5.0 is pretty good, but you can play with values). This also requires you to #import <QuartzCore/QuartzCore.h> in the file where you are setting this property.
All done!
If you are using IB to define views, you can set the subview clipping in IB but you can't modify the layer properties, so you'll have to add that part in viewDidLoad or somewhere similar.

Related

Draw part of a circle

For an iPhone application I want to draw a circle, that is only for an x percentage filled.
Something like this:
I have no problems calculating the radius, the degrees or the radians, that is no problem. Also drawing the circle is already done. But how do I get the iPhone SDK to draw the part that is filled.
I can draw a rectangle that size, but not part of a circle.
I just want to draw that on a a normal context.
Hope someone can give me any pointers here.
A lot of people have showed you how this can be done in Core Graphics but it can also be done with Core Animation which gives the big addition of easily being able to animate the percentage of the pie shape.
The following code will create both the ring and the partly filled layers (even though you said that you already can draw the ring) since its nice to have both the ring and the pie shape to be drawn using the same method.
If you animate the strokeStart or strokeEnd properties of the pieShape layer you will have the percentage animate. As with all Core Animation code you will need to add QuartzCore.framework to your project and include <QuartzCore/QuartzCore.h> in your code.
// Create a white ring that fills the entire frame and is 2 points wide.
// Its frame is inset 1 point to fit for the 2 point stroke width
CGFloat radius = MIN(self.frame.size.width,self.frame.size.height)/2;
CGFloat inset = 1;
CAShapeLayer *ring = [CAShapeLayer layer];
ring.path = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(self.bounds, inset, inset)
cornerRadius:radius-inset].CGPath;
ring.fillColor = [UIColor clearColor].CGColor;
ring.strokeColor = [UIColor whiteColor].CGColor;
ring.lineWidth = 2;
// Create a white pie-chart-like shape inside the white ring (above).
// The outside of the shape should be inside the ring, therefore the
// frame needs to be inset radius/2 (for its outside to be on
// the outside of the ring) + 2 (to be 2 points in).
CAShapeLayer *pieShape = [CAShapeLayer layer];
inset = radius/2 + 2; // The inset is updated here
pieShape.path = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(self.bounds, inset, inset)
cornerRadius:radius-inset].CGPath;
pieShape.fillColor = [UIColor clearColor].CGColor;
pieShape.strokeColor = [UIColor whiteColor].CGColor;
pieShape.lineWidth = (radius-inset)*2;
// Add sublayers
// NOTE: the following code is used in a UIView subclass (thus self is a view)
// If you instead chose to use this code in a view controller you should instead
// use self.view.layer to access the view of your view controller.
[self.layer addSublayer:ring];
[self.layer addSublayer:pieShape];
Use CGContext's arc functions:
CGContextAddArc(context,
centerX,
centerY,
radius,
startAngleRadians,
endAngleRadians,
clockwise ? 1 : 0);
See the documentation for CGContextAddArc().
Try this:
CGContextMoveToPoint(the center point)
CGContextAddLineToPoint(the starting point of the fill path on the circumference)
CGContextAddArcToPoint(the ending point of the fill path on the circumference)
CGContextAddLineToPoint(the center point)
CGContextFillPath
I implemented a pie progress view that looks similar to what you are doing. It's open source. Hopefully the source code will help.
SSPieProgressView.h source
SSPieProgressView.m source
CircleViewController.h
#import <UIKit/UIKit.h>
#interface CircleViewController : UIViewController
#end
CircleViewController.m
#import "CircleViewController.h"
#import "GraphView.h"
#interface CircleViewController ()
#end
#implementation CircleViewController
- (void)viewDidLoad {
[super viewDidLoad];
GraphView *graphView = [[GraphView alloc] initWithFrame:CGRectMake(100, 100, 200, 200)];
graphView.backgroundColor = [UIColor whiteColor];
graphView.layer.borderColor = [UIColor redColor].CGColor;
graphView.layer.borderWidth = 1.0f;
[self.view addSubview:graphView];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
GraphView.h
#import <UIKit/UIKit.h>
#interface GraphView : UIView
#end
GraphView.m
#import "GraphView.h"
#implementation GraphView
- (void)drawRect:(CGRect)rect {
CGPoint circleCenter = CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2);
[self drawCircleWithCircleCenter:(CGPoint) circleCenter radius:80 firstColor:[UIColor blueColor].CGColor secondeColor:[UIColor redColor].CGColor lineWidth:2 startDegree:0 currentDegree:90];
//[self drawCircleWithCircleCenter2:(CGPoint) circleCenter radius:80 firstColor:[UIColor blueColor].CGColor secondeColor:[UIColor redColor].CGColor lineWidth:2 startDegree:0 currentDegree:90];
}
- (void)drawCircleWithCircleCenter:(CGPoint) circleCenter
radius:(CGFloat)radius
firstColor:(CGColorRef)firstColor
secondeColor:(CGColorRef)secondeColor
lineWidth:(CGFloat)lineWidth
startDegree:(float)startDegree
currentDegree:(float)endDegree {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, lineWidth);
CGContextMoveToPoint(context, circleCenter.x, circleCenter.y);
CGContextAddArc(context, circleCenter.x , circleCenter.y, radius, [self radians:startDegree], [self radians:endDegree], 0);
CGContextSetFillColorWithColor(context, firstColor);
CGContextFillPath(context);
CGContextMoveToPoint(context, circleCenter.x, circleCenter.y);
CGContextAddArc(context, circleCenter.x, circleCenter.y, radius, [self radians:endDegree], [self radians:startDegree], 0);
CGContextSetFillColorWithColor(context, secondeColor);
CGContextFillPath(context);
}
- (void)drawCircleWithCircleCenter2:(CGPoint) circleCenter
radius:(CGFloat)radius
firstColor:(CGColorRef)firstColor
secondeColor:(CGColorRef)secondeColor
lineWidth:(CGFloat)lineWidth
startDegree:(float)startDegree
currentDegree:(float)endDegree {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, lineWidth);
CGContextMoveToPoint(context, circleCenter.x, circleCenter.y);
CGContextAddArc(context, circleCenter.x , circleCenter.y, radius, [self radians:startDegree], [self radians:endDegree], 0);
CGContextSetFillColorWithColor(context, firstColor);
CGContextFillPath(context);
CGContextMoveToPoint(context, circleCenter.x, circleCenter.y);
CGContextAddArc(context, circleCenter.x, circleCenter.y, radius, [self radians:endDegree], [self radians:startDegree], 0);
CGContextSetStrokeColorWithColor(context, secondeColor);
CGContextStrokePath(context);
}
-(float) radians:(double) degrees {
return degrees * M_PI / 180;
}
#end
note: you can use one of the 2 methods:
"drawCircleWithCircleCenter" or "drawCircleWithCircleCenter2"
this code if you want to split cell on 2 parts only
if you want to split cell on more than 2 parts you can check this : "Drawing a circle ,filled different parts with different color" and check the answer start with this Phrase "we have 6 class"
Well, since nobody used NSBezierPath so far, I figured I could provide the solution I recently used for the same problem:
-(void)drawRect:(NSRect)dirtyRect
{
double start = -10.0; //degrees
double end = 190.0; //degrees
NSPoint center = NSMakePoint(350, 200);
double radius = 50;
NSBezierPath *sector = [NSBezierPath bezierPath];
[sector moveToPoint:center];
[sector appendBezierPathWithArcWithCenter:center radius:radius startAngle:start endAngle:end];
[sector lineToPoint:center];
[sector fill];
}
Below is a full method I am using that does this with Core Graphics, adapting and expanding on mharper's comment above.
This code is for OSX Cocoa, but could easily be changed to iOS, by modifying how you get the context.
- (void)drawPieShapedCircleWithRadius:(CGFloat)radius
strokeColor:(CGColorRef)strokeColor
fillColor:(CGColorRef)fillColor
lineWidth:(CGFloat)lineWidth
currentDegrees:(float)currentDegrees
startDegrees:(float)startDegrees {
// get the context
CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
// Set the color of the circle stroke and fill
CGContextSetStrokeColorWithColor(context, strokeColor);
CGContextSetFillColorWithColor(context, fillColor);
// Set the line width of the circle
CGContextSetLineWidth(context, 1);
// Calculate the middle of the circle
CGPoint circleCenter = CGPointMake(self.frame.size.width / 2, self.frame.size.height / 2);
// Move the bezier to the center of the circle
CGContextMoveToPoint(context, circleCenter.x, circleCenter.y); // move to the center point
// Draw the arc from the start point (hardcoded as the bottom of the circle) to the center
CGContextAddLineToPoint(context, circleCenter.x, circleCenter.y + radius);
// Draw the arc around the circle from the start degrees point to the current degrees point
CGContextAddArc(context, circleCenter.x , circleCenter.y, radius, [self radians:startDegrees], [self radians:startDegrees + currentDegrees], 0);
// Draw the line back into the center of the circle
CGContextAddLineToPoint(context, circleCenter.x, circleCenter.y);
// Fill the circle
CGContextFillPath(context);
// Draw the line around the circle
CGContextStrokePath(context);
}
Try this code in a UIView, Example "MyChartClass"...
- (void)drawRect:(CGRect)rect {
int c=(int)[itemArray count];
CGFloat angleArray[c];
CGFloat offset;
int sum=0;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetAllowsAntialiasing(context, false);
CGContextSetShouldAntialias(context, false);
for(int i=0;i<[itemArray count];i++) {
sum+=[[itemArray objectAtIndex:i] intValue];
}
for(int i=0;i<[itemArray count];i++) {
angleArray[i]=(float)(([[itemArray objectAtIndex:i] intValue])/(float)sum)*(2*3.14);
CGContextMoveToPoint(context, radius, radius);
if(i==0)
CGContextAddArc(context, radius, radius, radius, 0,angleArray[i], 0);
else
CGContextAddArc(context, radius, radius, radius,offset,offset+angleArray[i], 0);
offset+=angleArray[i];
CGContextSetFillColorWithColor(context, ((UIColor *)[myColorArray objectAtIndex:i]).CGColor);
CGContextClosePath(context);
CGContextFillPath(context);
}
}
Implementation in your UIViewController
MyChartClass *myChartClass=[[MyChartClass alloc]initWithFrame:CGRectMake(0, 0, 200, 200)];
myChartClass.backgroundColor = [UIColor clearColor];
myChartClass.itemArray=[[NSArray alloc]initWithObjects:#"75",#"25", nil];
myChartClass.myColorArray=[[NSArray alloc]initWithObjects:[UIColor blackColor],[UIColor whiteColor], nil];
myChartClass.radius=100;
[self.view addSubview:myChartClass];
Regards.

How to draw a rounded rectangle in Core Graphics / Quartz 2D?

I need to draw an outline for a rounded rectangle. I know I can make lines and arcs, but maybe there is also a function for rounded rects?
Instead of making your own path out of lines and arcs, you can use
[UIBezierPath bezierPathWithRoundedRect:cornerRadius:]
or
[UIBezierPath bezierPathWithRoundedRect:byRoundingCorners:cornerRadii:]
(the second one lets you specify which corners are rounded)
Available in iOS 3.2 or later.
There is no prepackaged way to this, you must combine arcs in order to do this, apples quartzdemo project shows the code to do this, here is a reference Quartz Demo and here is the code they provide
// As a bonus, we'll combine arcs to create a round rectangle!
// Drawing with a white stroke color
CGContextRef context=UIGraphicsGetCurrentContext()
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0);
// If you were making this as a routine, you would probably accept a rectangle
// that defines its bounds, and a radius reflecting the "rounded-ness" of the rectangle.
CGRect rrect = CGRectMake(210.0, 90.0, 60.0, 60.0);
CGFloat radius = 10.0;
// NOTE: At this point you may want to verify that your radius is no more than half
// the width and height of your rectangle, as this technique degenerates for those cases.
// In order to draw a rounded rectangle, we will take advantage of the fact that
// CGContextAddArcToPoint will draw straight lines past the start and end of the arc
// in order to create the path from the current position and the destination position.
// In order to create the 4 arcs correctly, we need to know the min, mid and max positions
// on the x and y lengths of the given rectangle.
CGFloat minx = CGRectGetMinX(rrect), midx = CGRectGetMidX(rrect), maxx = CGRectGetMaxX(rrect);
CGFloat miny = CGRectGetMinY(rrect), midy = CGRectGetMidY(rrect), maxy = CGRectGetMaxY(rrect);
// Next, we will go around the rectangle in the order given by the figure below.
// minx midx maxx
// miny 2 3 4
// midy 1 9 5
// maxy 8 7 6
// Which gives us a coincident start and end point, which is incidental to this technique, but still doesn't
// form a closed path, so we still need to close the path to connect the ends correctly.
// Thus we start by moving to point 1, then adding arcs through each pair of points that follows.
// You could use a similar tecgnique to create any shape with rounded corners.
// Start at 1
CGContextMoveToPoint(context, minx, midy);
// Add an arc through 2 to 3
CGContextAddArcToPoint(context, minx, miny, midx, miny, radius);
// Add an arc through 4 to 5
CGContextAddArcToPoint(context, maxx, miny, maxx, midy, radius);
// Add an arc through 6 to 7
CGContextAddArcToPoint(context, maxx, maxy, midx, maxy, radius);
// Add an arc through 8 to 9
CGContextAddArcToPoint(context, minx, maxy, minx, midy, radius);
// Close the path
CGContextClosePath(context);
// Fill & stroke the path
CGContextDrawPath(context, kCGPathFillStroke);
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRoundedRect:bubbleBounds cornerRadius:15.0];
CGContextSetStrokeColorWithColor(context, [UIColor grayColor].CGColor);
[bezierPath stroke];
Here is a function I wrote that rounds the input rect using a corner radius.
CGMutablePathRef createRoundedCornerPath(CGRect rect, CGFloat cornerRadius) {
// create a mutable path
CGMutablePathRef path = CGPathCreateMutable();
// get the 4 corners of the rect
CGPoint topLeft = CGPointMake(rect.origin.x, rect.origin.y);
CGPoint topRight = CGPointMake(rect.origin.x + rect.size.width, rect.origin.y);
CGPoint bottomRight = CGPointMake(rect.origin.x + rect.size.width, rect.origin.y + rect.size.height);
CGPoint bottomLeft = CGPointMake(rect.origin.x, rect.origin.y + rect.size.height);
// move to top left
CGPathMoveToPoint(path, NULL, topLeft.x + cornerRadius, topLeft.y);
// add top line
CGPathAddLineToPoint(path, NULL, topRight.x - cornerRadius, topRight.y);
// add top right curve
CGPathAddQuadCurveToPoint(path, NULL, topRight.x, topRight.y, topRight.x, topRight.y + cornerRadius);
// add right line
CGPathAddLineToPoint(path, NULL, bottomRight.x, bottomRight.y - cornerRadius);
// add bottom right curve
CGPathAddQuadCurveToPoint(path, NULL, bottomRight.x, bottomRight.y, bottomRight.x - cornerRadius, bottomRight.y);
// add bottom line
CGPathAddLineToPoint(path, NULL, bottomLeft.x + cornerRadius, bottomLeft.y);
// add bottom left curve
CGPathAddQuadCurveToPoint(path, NULL, bottomLeft.x, bottomLeft.y, bottomLeft.x, bottomLeft.y - cornerRadius);
// add left line
CGPathAddLineToPoint(path, NULL, topLeft.x, topLeft.y + cornerRadius);
// add top left curve
CGPathAddQuadCurveToPoint(path, NULL, topLeft.x, topLeft.y, topLeft.x + cornerRadius, topLeft.y);
// return the path
return path;
}
How to use the function, assuming you subclass UIView and override drawRect:
- (void)drawRect:(CGRect)rect {
// constants
const CGFloat outlineStrokeWidth = 20.0f;
const CGFloat outlineCornerRadius = 15.0f;
const CGColorRef whiteColor = [[UIColor whiteColor] CGColor];
const CGColorRef redColor = [[UIColor redColor] CGColor];
// get the context
CGContextRef context = UIGraphicsGetCurrentContext();
// set the background color to white
CGContextSetFillColorWithColor(context, whiteColor);
CGContextFillRect(context, rect);
// inset the rect because half of the stroke applied to this path will be on the outside
CGRect insetRect = CGRectInset(rect, outlineStrokeWidth/2.0f, outlineStrokeWidth/2.0f);
// get our rounded rect as a path
CGMutablePathRef path = createRoundedCornerPath(insetRect, outlineCornerRadius);
// add the path to the context
CGContextAddPath(context, path);
// set the stroke params
CGContextSetStrokeColorWithColor(context, redColor);
CGContextSetLineWidth(context, outlineStrokeWidth);
// draw the path
CGContextDrawPath(context, kCGPathStroke);
// release the path
CGPathRelease(path);
}
Example output:
If you want To have rounded corners on any UIView (or subclass) the easy way is to set the cornerRadius property on the view's layer. See Preview rounded image in iphone
CGPathCreateWithRoundedRect() will do what you want.
CGPathRef CGPathCreateWithRoundedRect(
CGRect rect,
CGFloat cornerWidth,
CGFloat cornerHeight,
const CGAffineTransform *transform
);
Available starting in iOS 7.0
Swift:
let rect: CGRect = ...
let path = UIBezierPath(roundedRect: rect, cornerRadius: 5.0)
context.addPath(path.cgPath)
context.setStrokeColor(UIColor.clear.cgColor)
context.drawPath(using: .fillStroke)
Maybe... three? years late, but these days I'm using this without issues.
#import CoreGraphics;
#interface YourViewController ()
#property (weak, nonatomic) IBOutlet UIButton *theButton;
#end
- (void)viewDidLoad
{
[super viewDidLoad];
self.theButton.layer.cornerRadius = 5.0f;
self.theButton.layer.masksToBounds = YES;
// Another useful ones
// Scaling the view (width, height)
self.theButton.transform = CGAfflineTransformMakeScale(1.50f, 1.50f);
// Setting an alpha value (transparency) - nice with Activity Indicator subviews
self.theButton.alpha = 0.8f;
}
Swift 4.2
let lineWidth: CGFloat = 5.0
let path = UIBezierPath(roundedRect: rect.insetBy(dx: lineWidth/2.0, dy: lineWidth/2.0), cornerRadius: 10。0)
path.lineWidth = lineWidth
UIColor.green.setStroke()
path.stroke()

How to change Background of alert ? and can we change its position?

How to change Background of alert? and can we change its position?
I mean is it possible to display it up or down?
Is there any sample code available?
Thanks in advance.
You cannot through any Apple supported API methods. The advised way of customizing look and feel of a UIAlertView is to create your own.
From the iPhone Human Interface Guidelines:
You can specify the text, the number
of buttons, and the button contents in
an alert, but you can’t customize the
background appearance of the alert
itself.
Unless you have a very good reason for wanting to customize the background color or other properties of the alert, don't do it. Your application will clash with the rest of the system, and may be rejected for violating the above-mentioned human interface guidelines. Again, from the iPhone Human Interface Guidelines:
Because users are accustomed to the
appearance and behavior of these
views, it’s important to use them
consistently and correctly in your
application.
U can change the color.But i do no about position.Create CustomAlert which inherits from Alert.In drawRect: u can specify color u want in CGContextSetRGBFillColor method.
Here is implementation.
#implementation CustomAlert
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
// Initialization code
}
return self;
}
// Method which will draw the actual view
- (void)drawRect:(CGRect)rect {
CGContextRef context=UIGraphicsGetCurrentContext();
UIColor *color = [UIColor purpleColor];
const CGFloat *arr= CGColorGetComponents(color.CGColor);
CGContextSetRGBStrokeColor(context,0, 0, 0, 1.0);
CGContextSetRGBFillColor(context, arr[0], arr[1], arr[2], 0.85);
CGContextSetLineWidth(context, 1.0);
addRoundedRectToPath(context, rect);
// Drawing final path
CGContextDrawPath(context, kCGPathFill);
}
- (void)dealloc {
[super dealloc];
}
#end
static void addRoundedRectToPath(CGContextRef context, CGRect rect){
CGFloat radius = 10;
CGFloat minx = CGRectGetMinX(rect), midx = CGRectGetMidX(rect), maxx = CGRectGetMaxX(rect);
CGFloat miny = CGRectGetMinY(rect), midy = CGRectGetMidY(rect), maxy = CGRectGetMaxY(rect);
CGContextMoveToPoint(context, minx, midy);
// Add an arc through 2 to 3
CGContextAddArcToPoint(context, minx, miny, midx, miny, radius);
// Add an arc through 4 to 5
CGContextAddArcToPoint(context, maxx, miny, maxx, midy, radius);
// Add an arc through 6 to 7
CGContextAddArcToPoint(context, maxx, maxy, midx, maxy, radius);
// Add an arc through 8 to 9
CGContextAddArcToPoint(context, minx, maxy, minx, midy, radius);
CGContextClosePath(context);
}

UITableViewCell rounded corners and clip subviews

I can't find anything anywhere(search engines, docs, here, etc) that shows how to create rounded corners (esp. in a grouped table view) on an element that also clips the subviews.
I have code that properly creates a rounded rectangle out of a path with 4 arcs(the rounded corners) that has been tested in the drawRect: method in my subclassed uitableviewcell. The issue is that the subviews, which happen to be uibuttons with their internal uiimageviews, do no obey the CGContextClip() that the uitableviewcell obeys.
Here is the code:
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGFloat radius = 12;
CGFloat width = CGRectGetWidth(rect);
CGFloat height = CGRectGetHeight(rect);
// Make sure corner radius isn't larger than half the shorter side
if (radius > width/2.0)
radius = width/2.0;
if (radius > height/2.0)
radius = height/2.0;
CGFloat minx = CGRectGetMinX(rect) + 10;
CGFloat midx = CGRectGetMidX(rect);
CGFloat maxx = CGRectGetMaxX(rect) - 10;
CGFloat miny = CGRectGetMinY(rect);
CGFloat midy = CGRectGetMidY(rect);
CGFloat maxy = CGRectGetMaxY(rect);
[[UIColor greenColor] set];
CGContextBeginPath(context);
CGContextMoveToPoint(context, minx, midy);
CGContextAddArcToPoint(context, minx, miny, midx, miny, radius);
CGContextAddArcToPoint(context, maxx, miny, maxx, midy, radius);
CGContextAddArcToPoint(context, maxx, maxy, midx, maxy, radius);
CGContextAddArcToPoint(context, minx, maxy, minx, midy, radius);
CGContextClip(context);
CGContextFillRect(context, rect);
[super drawRect:rect];
}
Because this specific case is static(only shows in 1 specific row of buttons), I can edit the images being used for the buttons to get the desired effect.
HOWEVER, I have another case that is dynamic. Specifically, a grouped table with lots of database-driven results that will show photos that may be in the first or last row with rounded corners and thus needs to be clipped).
So, is it possible to create a CGContextClip() that also clips the subviews? If so, how?
The CALayer object has functions for rounding corners:
UIView * someview = something here;
CALayer * layer = [someview layer];
layer.masksToBounds = YES;
layer.cornerRadius = radius;
And you're all set. You can also add some border colors and stuff, check out the docs in case you're interested.
See this code: http://gist.github.com/292384
I've used it in multiple projects, the performance is great and it's highly customizable. It doesn't use cornerRadius and the drawing of the cells is context-sensitive.
Try this in your view initialiser:
self.layer.borderWidth = 2.0f;
self.layer.borderColor = [[UIColor greenColor] CGColor];
self.layer.masksToBounds = YES;
self.layer.cornerRadius = 12.0f;
And then you don't need to implement any drawRect method at all (at least for the purposes of the round border and clipping.)
Create a subclass of UIImageView with rounded corners and transparency. The UITableViewCell itself should be opaque for better performance.
Have a look at this example.
If you have a custom UITableViewCell you can do this in Swift 4.0:
class CustomTVC: UITableViewCell {
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
self.layer.cornerRadius = 20
self.layer.masksToBounds = true
}
}

How can I clear the corners outside of a rounded rect using the iPhone SDK?

I am attempting to implement a custom view. This view should display an image surrounded by a gray, rounded rect border. I can get the image to display fine, as well as the border, however, since the border has rounded corners, I need a way to clear those corners such that they correctly display whatever is behind the view. How can I accomplish this?
It seems like I might be able to use CGContextClearRect, but then wouldn't I have to call this multiple times, reconstructing the area outside of my rounded corner? That sounds overly complicated.
Is there a better way to create this view?
Here is my current code:
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
// Draw the image. This will completely fill the current rect.
[image drawInRect:self.bounds];
// Ensure we draw completely within our bounds instead of straddling it.
CGRect rrect = self.bounds;
rrect.size.height = rrect.size.height - 1.0;
rrect.size.width = rrect.size.width - 1.0;
rrect.origin.x = rrect.origin.x + (1.0 / 2);
rrect.origin.y = rrect.origin.y + (1.0 / 2);
CGFloat radius = 5.0;
CGFloat minx = CGRectGetMinX(rrect);
CGFloat midx = CGRectGetMidX(rrect);
CGFloat maxx = CGRectGetMaxX(rrect);
CGFloat miny = CGRectGetMinY(rrect);
CGFloat midy = CGRectGetMidY(rrect);
CGFloat maxy = CGRectGetMaxY(rrect);
// Draw the rounded rect border.
CGContextSetRGBStrokeColor(context, 0.6, 0.6, 0.6, 1.0);
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 0.0);
CGContextSetLineWidth(context, 1.0);
CGContextMoveToPoint(context, minx, midy);
CGContextAddArcToPoint(context, minx, miny, midx, miny, radius);
CGContextAddArcToPoint(context, maxx, miny, maxx, midy, radius);
CGContextAddArcToPoint(context, maxx, maxy, midx, maxy, radius);
CGContextAddArcToPoint(context, minx, maxy, minx, midy, radius);
CGContextClosePath(context);
CGContextDrawPath(context, kCGPathFillStroke);
}
Add the rounded-rect path to the clipping path before drawing the image.
Last week I was trying to do something similar.
With your question, the answer and other Q&A I created an example with a solution.
https://github.com/GabrielMassana/TransparentRoudRectButton