2010-05-14 2 views
60

Мне нужно нарисовать контур округлого прямоугольника. Я знаю, что могу создавать линии и дуги, но, возможно, есть функция для закругленных прямоугольников?Как нарисовать округленный прямоугольник в Core Graphics/Quartz 2D?

+0

пример кода http://stackoverflow.com/a/19142851/294884 – Fattie

ответ

55

Там нет расфасованного пути к этому, вы должны объединить дуги, чтобы сделать это, яблоки quartzdemo проекта показывает код, чтобы сделать это, вот ссылка Quartz Demo и вот код, который они обеспечивают

// 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); 
+3

Если кто-то интересно, как 'CGContextAddArcToPoint()' работы, [это] (HTTP : //stackoverflow.com/a/18992153/1338292) - довольно хорошее объяснение. –

11

Если вы хотите иметь закругленные углы на любом UIView (или подклассе), то простой способ - установить свойство cornerRadius на уровне представления. См Preview rounded image in iphone

+4

Это, безусловно, самый простой. view.layer.cornerRadius = 10.0f. Убедитесь, что вы импортируете каркас кварца. –

123

Вместо того, чтобы сделать свой собственный путь из линий и дуг, вы можете использовать

[UIBezierPath bezierPathWithRoundedRect:cornerRadius:] 

или

[UIBezierPath bezierPathWithRoundedRect:byRoundingCorners:cornerRadii:] 

(второй позволяет указать, какие углы закруглены)

Доступен в iOS версии 3.2 или новее.

+7

Не забудьте правильно вставить прямоугольник при поглаживании, даже если ваша ширина линии - только один пиксель: 'CGRectInset (rect, lineWidth, lineWidth)' – pottedmeat

+20

Для полноты также полезно показать, что вы делаете с этим: ' '' objc [[UIColor lightGrayColor] setFill]; // установить округленный прямоугольник bg color UIBezierPath * roundedRect = [UIBezierPath bezierPathWithRoundedRect: _yourDrawingFrame cornerRadius: 4]; [roundedRect fillWithBlendMode: kCGBlendModeNormal alpha: 1.0f]; '' ' – horseshoe7

+9

На самом деле при поглаживании я считаю, что прямоугольник должен быть вставлен только в половину строки. Ширина i.e.' CGRectInset (rect, lineWidth/2.0, lineWidth/2.0) '. Это связано с тем, что «вытянутая линия центрирована по пути с ее сторонами, параллельными сегменту пути» (см. '- [UIBezierPath strokeWithBlendMode: alpha:]') – Taum

22

Вот функция, которую я написал, которая округляет входной прямоугольник, используя радиус угла.

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

Как использовать эту функцию, если вы подкласс UIView и переопределить 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); 
} 

Пример вывода:

enter image description here

+0

, но почему бы не использовать встроенные функции ?????????? – Fattie

+0

Вперед и используйте встроенные функции. Я сделал это только для обучения. –

+0

Это не работает: CGMutablePathRef path = createRoundedCornerPath (insetRect, outlineCornerRadius); – lespommes

41
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRoundedRect:bubbleBounds cornerRadius:15.0]; 
CGContextSetStrokeColorWithColor(context, [UIColor grayColor].CGColor); 
[bezierPath stroke]; 
9

CGPathCreateWithRoundedRect() будет делать то, что вы хотите.

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

Доступно начиная с прошивкой 7.0

+3

Я уверен, что это НЕ ДАЕТ ВАС новые закругленные углы iOS7. Используйте bezierPathWithRoundedRect для новых закругленных углов iOS7 ... – Fattie

+0

@JoeBlow Не уверен, что вы подразумеваете под этим, эта функция была добавлена ​​только в iOS7 и дает закругленные углы; есть ли еще закругленные углы? –

+0

http://www.mani.de/backstage/?p=483 – Fattie

1

Может быть ... три? лет поздно, но в эти дни я использую это без проблем.

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

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) 
Смежные вопросы