如何在 Core Graphics / Quartz 2D 中绘制圆角矩形?
Posted
技术标签:
【中文标题】如何在 Core Graphics / Quartz 2D 中绘制圆角矩形?【英文标题】:How to draw a rounded rectangle in Core Graphics / Quartz 2D? 【发布时间】:2011-02-19 14:19:53 【问题描述】:我需要画一个圆角矩形的轮廓。我知道我可以制作直线和圆弧,但也许还有圆角矩形的功能?
【问题讨论】:
示例代码***.com/a/19142851/294884 【参考方案1】:没有预先打包的方法,您必须结合弧才能做到这一点,apples 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);
【讨论】:
如果有人想知道CGContextAddArcToPoint()
的工作原理,this 是一个很好的解释。【参考方案2】:
斯威夫特 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()
【讨论】:
【参考方案3】:斯威夫特:
let rect: CGRect = ...
let path = UIBezierPath(roundedRect: rect, cornerRadius: 5.0)
CGContextAddPath(context, path.CGPath)
CGContextSetStrokeColorWithColor(context, UIColor.clearColor().CGColor)
CGContextDrawPath(context, CGPathDrawingMode.FillStroke)
【讨论】:
【参考方案4】:也许……三个?晚了几年,但这些天我使用它没有问题。
@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;
【讨论】:
【参考方案5】:CGPathCreateWithRoundedRect()
会做你想做的事。
CGPathRef CGPathCreateWithRoundedRect(
CGRect rect,
CGFloat cornerWidth,
CGFloat cornerHeight,
const CGAffineTransform *transform
);
从 ios 7.0 开始提供
【讨论】:
我很确定这不会给你新的 iOS7 圆角。对新的 iOS7 圆角使用 bezierPathWithRoundedRect... @JoeBlow 不知道你的意思,这个功能只在iOS7中添加,给你圆角;还有其他圆角吗?【参考方案6】: UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRoundedRect:bubbleBounds cornerRadius:15.0];
CGContextSetStrokeColorWithColor(context, [UIColor grayColor].CGColor);
[bezierPath stroke];
【讨论】:
【参考方案7】:这是我编写的一个函数,它使用角半径对输入矩形进行四舍五入。
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);
示例输出:
【讨论】:
继续使用内置函数。我做这个只是为了学习。 这不起作用:CGMutablePathRef path = createRoundedCornerPath(insetRect, outlineCornerRadius); 确保您已经复制了我的回复中包含的 createRoundedCornerPath() 函数的实现。它也必须放在 drawRect: 方法之上,因为它是一个 C 函数。 看看 BezierPath。更容易画出这样的想法【参考方案8】:您可以使用
[UIBezierPath bezierPathWithRoundedRect:cornerRadius:]
或
[UIBezierPath bezierPathWithRoundedRect:byRoundingCorners:cornerRadii:]
(第二个让你指定哪些角是圆角)
适用于 iOS 3.2 或更高版本。
【讨论】:
即使你的线宽只有一个像素,也不要忘记在描边时正确插入矩形:CGRectInset(rect, lineWidth, lineWidth)
为了完整起见,展示您的处理方式也很有帮助:objc [[UIColor lightGrayColor] setFill]; // set rounded rect's bg color UIBezierPath *roundedRect = [UIBezierPath bezierPathWithRoundedRect: _yourDrawingFrame cornerRadius: 4]; [roundedRect fillWithBlendMode: kCGBlendModeNormal alpha:1.0f];
实际上在抚摸时我相信矩形应该只插入 lineWidth 的一半,即CGRectInset(rect, lineWidth/2.0, lineWidth/2.0)
。这是因为“绘制的线以路径为中心,其两侧与路径段平行”(参见-[UIBezierPath strokeWithBlendMode:alpha:]
)
如果您更喜欢 CoreGraphics 方法并仅支持 iOS 7.0 及更高版本,也可以使用 CGPathAddRoundedRect
。【参考方案9】:
如果您想在任何 UIView(或子类)上使用圆角,简单的方法是在视图层上设置cornerRadius 属性。见Preview rounded image in iphone
【讨论】:
这是迄今为止最简单的。 view.layer.cornerRadius = 10.0f。确保导入 Quartz 框架。以上是关于如何在 Core Graphics / Quartz 2D 中绘制圆角矩形?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Core Graphics / Quartz 2D 中绘制圆角矩形?
如何将 Accelerate Framework 与 Core Graphics 一起使用?