Come disegnare un rettangolo arrotondato in Core Graphics / Quartz 2D?

Devo disegnare un contorno per un rettangolo arrotondato. So che posso creare linee e archi, ma forse c’è anche una funzione per le tacche arrotondate?

Invece di creare il tuo percorso da linee e archi, puoi usarlo

[UIBezierPath bezierPathWithRoundedRect:cornerRadius:] 

o

 [UIBezierPath bezierPathWithRoundedRect:byRoundingCorners:cornerRadii:] 

(il secondo ti consente di specificare quali angoli sono arrotondati)

Disponibile in iOS 3.2 o successive.

Non esiste un modo precompilato per questo, è necessario combinare gli archi per fare ciò, il progetto mele quartzdemo mostra il codice per farlo, ecco una Demo di riferimento Quartz ed ecco il codice che forniscono

  // 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]; 

Ecco una funzione che ho scritto che arrotonda l’input rect usando un raggio d’angolo.

 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; } 

Come utilizzare la funzione, assumendo la sottoclass UIView e sovrascrivi 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); } 

Esempio di output:

inserisci la descrizione dell'immagine qui

Se si desidera avere angoli arrotondati su qualsiasi UIView (o sottoclass), il modo semplice è impostare la proprietà cornerRadius sul livello della vista. Vedi Anteprima immagine arrotondata in iphone

CGPathCreateWithRoundedRect() farà ciò che vuoi.

 CGPathRef CGPathCreateWithRoundedRect( CGRect rect, CGFloat cornerWidth, CGFloat cornerHeight, const CGAffineTransform *transform ); 

Disponibile a partire da iOS 7.0

Swift:

  let rect: CGRect = ... let path = UIBezierPath(roundedRect: rect, cornerRadius: 5.0) CGContextAddPath(context, path.CGPath) CGContextSetStrokeColorWithColor(context, UIColor.clearColor().CGColor) CGContextDrawPath(context, CGPathDrawingMode.FillStroke) 

Forse … tre? anni tardi, ma in questi giorni sto usando questo senza problemi.

 @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; }