如何在 iOS Swift 中画一个圆圈?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29616992/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I draw a circle in iOS Swift?
提问by TIMEX
let block = UIView(frame: CGRectMake(cellWidth-25, cellHeight/2-8, 16, 16))
block.backgroundColor = UIColor(netHex: 0xff3b30)
block.layer.cornerRadius = 9
block.clipsToBounds = true
This is what I have right now, but it's obviously not the right way to do it.
这就是我现在所拥有的,但这显然不是正确的方法。
What's the simplest way to do it?
最简单的方法是什么?
回答by Dario
WARNING!This is an incorrect solution. layers are added infinitely in the
drawRect
method (every time the view is drawn). You should NEVER add layers in thedrawRect
method. UselayoutSubview
instead.
警告!这是一个不正确的解决方案。在
drawRect
方法中无限添加图层(每次绘制视图时)。你永远不应该在drawRect
方法中添加层。使用layoutSubview
来代替。
You can draw a circle with this (Swift 3.0+):
你可以用这个(Swift 3.0+)画一个圆圈:
let circlePath = UIBezierPath(arcCenter: CGPoint(x: 100, y: 100), radius: CGFloat(20), startAngle: CGFloat(0), endAngle: CGFloat(Double.pi * 2), clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.cgPath
// Change the fill color
shapeLayer.fillColor = UIColor.clear.cgColor
// You can change the stroke color
shapeLayer.strokeColor = UIColor.red.cgColor
// You can change the line width
shapeLayer.lineWidth = 3.0
view.layer.addSublayer(shapeLayer)
With the code you have posted you are cropping the corners of the UIView
, not adding a circle to the view.
使用您发布的代码,您正在裁剪 的角,而UIView
不是在视图中添加圆圈。
Here's a full example of using that method:
这是使用该方法的完整示例:
/// A special UIView displayed as a ring of color
class Ring: UIView {
override func drawRect(rect: CGRect) {
drawRingFittingInsideView()
}
internal func drawRingFittingInsideView() -> () {
let halfSize:CGFloat = min( bounds.size.width/2, bounds.size.height/2)
let desiredLineWidth:CGFloat = 1 // your desired value
let circlePath = UIBezierPath(
arcCenter: CGPoint(x:halfSize,y:halfSize),
radius: CGFloat( halfSize - (desiredLineWidth/2) ),
startAngle: CGFloat(0),
endAngle:CGFloat(M_PI * 2),
clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.CGPath
shapeLayer.fillColor = UIColor.clearColor().CGColor
shapeLayer.strokeColor = UIColor.redColor().CGColor
shapeLayer.lineWidth = desiredLineWidth
layer.addSublayer(shapeLayer)
}
}
Note, however there's an incredibly handy call:
请注意,但是有一个非常方便的调用:
let circlePath = UIBezierPath(ovalInRect: rect)
let circlePath = UIBezierPath(ovalInRect: rect)
which does all the work of making the path. (Don't forget to inset it for the line thickness, which is also incredibly easy with CGRectInset
.)
它完成了制作路径的所有工作。(不要忘记为线条粗细插入它,这也非常容易使用CGRectInset
。)
internal func drawRingFittingInsideView(rect: CGRect) {
let desiredLineWidth:CGFloat = 4 // Your desired value
let hw:CGFloat = desiredLineWidth/2
let circlePath = UIBezierPath(ovalInRect: CGRectInset(rect,hw,hw))
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.CGPath
shapeLayer.fillColor = UIColor.clearColor().CGColor
shapeLayer.strokeColor = UIColor.redColor().CGColor
shapeLayer.lineWidth = desiredLineWidth
layer.addSublayer(shapeLayer)
}
In practice these days in Swift, you would certainly use @IBDesignable
and @IBInspectable
. Using these you can actually see and change the rendering, in Storyboard!
现在在 Swift 中的实践中,您肯定会使用@IBDesignable
和@IBInspectable
。使用这些,您可以在 Storyboard 中实际查看和更改渲染!
As you can see, it actually adds new features to the Inspector on the Storyboard, which you can change on the Storyboard:
如您所见,它实际上为 Storyboard 上的 Inspector 添加了新功能,您可以在 Storyboard 上更改这些功能:
/// A dot with a border, which you can control completely in Storyboard
@IBDesignable class Dot: UIView {
@IBInspectable var mainColor: UIColor = UIColor.blueColor() {
didSet {
print("mainColor was set here")
}
}
@IBInspectable var ringColor: UIColor = UIColor.orangeColor() {
didSet {
print("bColor was set here")
}
}
@IBInspectable var ringThickness: CGFloat = 4 {
didSet {
print("ringThickness was set here")
}
}
@IBInspectable var isSelected: Bool = true
override func drawRect(rect: CGRect) {
let dotPath = UIBezierPath(ovalInRect:rect)
let shapeLayer = CAShapeLayer()
shapeLayer.path = dotPath.CGPath
shapeLayer.fillColor = mainColor.CGColor
layer.addSublayer(shapeLayer)
if (isSelected) {
drawRingFittingInsideView(rect)
}
}
internal func drawRingFittingInsideView(rect: CGRect) {
let hw:CGFloat = ringThickness/2
let circlePath = UIBezierPath(ovalInRect: CGRectInset(rect,hw,hw) )
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.CGPath
shapeLayer.fillColor = UIColor.clearColor().CGColor
shapeLayer.strokeColor = ringColor.CGColor
shapeLayer.lineWidth = ringThickness
layer.addSublayer(shapeLayer)
}
}
Finally, note that if you have a UIView
(which is square, and which you set to say red in Storyboard) and you simply want to turn it in to a red circle, you can just do the following:
最后,请注意,如果您有一个UIView
(它是正方形,并且在 Storyboard 中设置为红色)并且您只想将其变成红色圆圈,则可以执行以下操作:
// Makes a UIView into a circular dot of color
class Dot: UIView {
override func layoutSubviews() {
layer.cornerRadius = bounds.size.width/2
}
}
回答by Oxcug
If you want to use a UIView to draw it, then you need to make the radius / of the height or width.
如果你想使用 UIView 来绘制它,那么你需要制作高度或宽度的半径 / 。
so just change:
所以只需改变:
block.layer.cornerRadius = 9
to:
到:
block.layer.cornerRadius = block.frame.width / 2
You'll need to make the height and width the same however. If you'd like to use coregraphics, then you'll want to do something like this:
但是,您需要使高度和宽度相同。如果你想使用 coregraphics,那么你会想要做这样的事情:
CGContextRef ctx= UIGraphicsGetCurrentContext();
CGRect bounds = [self bounds];
CGPoint center;
center.x = bounds.origin.x + bounds.size.width / 2.0;
center.y = bounds.origin.y + bounds.size.height / 2.0;
CGContextSaveGState(ctx);
CGContextSetLineWidth(ctx,5);
CGContextSetRGBStrokeColor(ctx,0.8,0.8,0.8,1.0);
CGContextAddArc(ctx,locationOfTouch.x,locationOfTouch.y,30,0.0,M_PI*2,YES);
CGContextStrokePath(ctx);
回答by MadProgrammer
Make a class UIView and assign it this code for a simple circle
创建一个类 UIView 并将此代码分配给一个简单的圆圈
import UIKit
@IBDesignable
class DRAW: UIView {
override func draw(_ rect: CGRect) {
var path = UIBezierPath()
path = UIBezierPath(ovalIn: CGRect(x: 50, y: 50, width: 100, height: 100))
UIColor.yellow.setStroke()
UIColor.red.setFill()
path.lineWidth = 5
path.stroke()
path.fill()
}
}
回答by Jacob F. Davis C-CISO
Updating @Dario's code approach for Xcode 8.2.2, Swift 3.x. Noting that in storyboard, set the Background color to "clear" to avoid a black background in the square UIView:
为 Xcode 8.2.2、Swift 3.x 更新 @Dario 的代码方法。请注意,在 storyboard 中,将背景颜色设置为“清除”以避免方形 UIView 中的黑色背景:
import UIKit
@IBDesignable
class Dot:UIView
{
@IBInspectable var mainColor: UIColor = UIColor.clear
{
didSet { print("mainColor was set here") }
}
@IBInspectable var ringColor: UIColor = UIColor.clear
{
didSet { print("bColor was set here") }
}
@IBInspectable var ringThickness: CGFloat = 4
{
didSet { print("ringThickness was set here") }
}
@IBInspectable var isSelected: Bool = true
override func draw(_ rect: CGRect)
{
let dotPath = UIBezierPath(ovalIn: rect)
let shapeLayer = CAShapeLayer()
shapeLayer.path = dotPath.cgPath
shapeLayer.fillColor = mainColor.cgColor
layer.addSublayer(shapeLayer)
if (isSelected) { drawRingFittingInsideView(rect: rect) }
}
internal func drawRingFittingInsideView(rect: CGRect)->()
{
let hw:CGFloat = ringThickness/2
let circlePath = UIBezierPath(ovalIn: rect.insetBy(dx: hw,dy: hw) )
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.cgPath
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = ringColor.cgColor
shapeLayer.lineWidth = ringThickness
layer.addSublayer(shapeLayer)
}
}
And if you want to control the start and end angles:
如果你想控制开始和结束角度:
import UIKit
@IBDesignable
class Dot:UIView
{
@IBInspectable var mainColor: UIColor = UIColor.clear
{
didSet { print("mainColor was set here") }
}
@IBInspectable var ringColor: UIColor = UIColor.clear
{
didSet { print("bColor was set here") }
}
@IBInspectable var ringThickness: CGFloat = 4
{
didSet { print("ringThickness was set here") }
}
@IBInspectable var isSelected: Bool = true
override func draw(_ rect: CGRect)
{
let dotPath = UIBezierPath(ovalIn: rect)
let shapeLayer = CAShapeLayer()
shapeLayer.path = dotPath.cgPath
shapeLayer.fillColor = mainColor.cgColor
layer.addSublayer(shapeLayer)
if (isSelected) { drawRingFittingInsideView(rect: rect) }
}
internal func drawRingFittingInsideView(rect: CGRect)->()
{
let halfSize:CGFloat = min( bounds.size.width/2, bounds.size.height/2)
let desiredLineWidth:CGFloat = ringThickness // your desired value
let circlePath = UIBezierPath(
arcCenter: CGPoint(x: halfSize, y: halfSize),
radius: CGFloat( halfSize - (desiredLineWidth/2) ),
startAngle: CGFloat(0),
endAngle:CGFloat(Double.pi),
clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.cgPath
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = ringColor.cgColor
shapeLayer.lineWidth = ringThickness
layer.addSublayer(shapeLayer)
}
}
回答by atereshkov
Swift 4version of accepted answer:
Swift 4版本已接受的答案:
@IBDesignable
class CircledDotView: UIView {
@IBInspectable var mainColor: UIColor = .white {
didSet { print("mainColor was set here") }
}
@IBInspectable var ringColor: UIColor = .black {
didSet { print("bColor was set here") }
}
@IBInspectable var ringThickness: CGFloat = 4 {
didSet { print("ringThickness was set here") }
}
@IBInspectable var isSelected: Bool = true
override func draw(_ rect: CGRect) {
let dotPath = UIBezierPath(ovalIn: rect)
let shapeLayer = CAShapeLayer()
shapeLayer.path = dotPath.cgPath
shapeLayer.fillColor = mainColor.cgColor
layer.addSublayer(shapeLayer)
if (isSelected) {
drawRingFittingInsideView(rect: rect)
}
}
internal func drawRingFittingInsideView(rect: CGRect) {
let hw: CGFloat = ringThickness / 2
let circlePath = UIBezierPath(ovalIn: rect.insetBy(dx: hw, dy: hw))
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.cgPath
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = ringColor.cgColor
shapeLayer.lineWidth = ringThickness
layer.addSublayer(shapeLayer)
}
}
回答by biomiker
I find Core Graphics to be pretty simple for Swift 3:
我发现 Core Graphics 对于Swift 3 来说非常简单:
if let cgcontext = UIGraphicsGetCurrentContext() {
cgcontext.strokeEllipse(in: CGRect(x: center.x-diameter/2, y: center.y-diameter/2, width: diameter, height: diameter))
}
回答by Ankit Kushwah
Add in view did load
在视图中添加确实加载
//Circle Points
var CircleLayer = CAShapeLayer()
let center = CGPoint (x: myCircleView.frame.size.width / 2, y: myCircleView.frame.size.height / 2)
let circleRadius = myCircleView.frame.size.width / 2
let circlePath = UIBezierPath(arcCenter: center, radius: circleRadius, startAngle: CGFloat(M_PI), endAngle: CGFloat(M_PI * 4), clockwise: true)
CircleLayer.path = circlePath.cgPath
CircleLayer.strokeColor = UIColor.red.cgColor
CircleLayer.fillColor = UIColor.blue.cgColor
CircleLayer.lineWidth = 8
CircleLayer.strokeStart = 0
CircleLayer.strokeEnd = 1
Self.View.layer.addSublayer(CircleLayer)
回答by tryp
A simple function drawing a circle on the middle of your window frame, using a multiplicator percentage
一个简单的函数,在窗口框架的中间绘制一个圆圈,使用乘数百分比
/// CGFloat is a multiplicator from self.view.frame.width
func drawCircle(withMultiplicator coefficient: CGFloat) {
let radius = self.view.frame.width / 2 * coefficient
let circlePath = UIBezierPath(arcCenter: self.view.center, radius: radius, startAngle: CGFloat(0), endAngle:CGFloat(Double.pi * 2), clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.cgPath
//change the fill color
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = UIColor.darkGray.cgColor
shapeLayer.lineWidth = 2.0
view.layer.addSublayer(shapeLayer)
}
回答by Paul Wasilewski
A much easier and resource friendly approach would be.
一个更容易和资源友好的方法是。
import UIKit
@IBDesignable
class CircleDrawView: UIView {
@IBInspectable var borderColor: UIColor = UIColor.red;
@IBInspectable var borderSize: CGFloat = 4
override func draw(_ rect: CGRect)
{
layer.borderColor = borderColor.cgColor
layer.borderWidth = borderSize
layer.cornerRadius = self.frame.height/2
}
}
With Border Color
and Border Size
and the default Background
property you can define the appearance of the circle.
使用Border Color
和Border Size
和默认Background
属性可以定义圆的外观。
Please note, to draw a circle the view's height and width have to be equal in size.
请注意,要绘制圆形,视图的高度和宽度必须大小相等。
The code is working for Swift >= 4
and Xcode >= 9
.
该代码适用于Swift >= 4
和Xcode >= 9
。
回答by paulo62
Here is my version using Swift 5 and Core Graphics.
这是我使用 Swift 5 和 Core Graphics 的版本。
I have created a class to draw two circles. The first circle is created using addEllipse()
. It puts the ellipse into a square, thus creating a circle. I find it surprising that there is no function addCircle()
. The second circle is created using addArc()
of 2pi radians
我创建了一个类来绘制两个圆圈。第一个圆是使用addEllipse()
. 它将椭圆放入一个正方形,从而创建一个圆。没有函数,我觉得很奇怪addCircle()
。第二个圆是使用addArc()
2pi 弧度创建的
import UIKit
@IBDesignable
class DrawCircles: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func draw(_ rect: CGRect) {
guard let context = UIGraphicsGetCurrentContext() else {
print("could not get graphics context")
return
}
context.setLineWidth(2)
context.setStrokeColor(UIColor.blue.cgColor)
context.addEllipse(in: CGRect(x: 30, y: 30, width: 50.0, height: 50.0))
context.strokePath()
context.setStrokeColor(UIColor.red.cgColor)
context.beginPath() // this prevents a straight line being drawn from the current point to the arc
context.addArc(center: CGPoint(x:100, y: 100), radius: 20, startAngle: 0, endAngle: 2.0*CGFloat.pi, clockwise: false)
context.strokePath()
}
}
in your ViewController's didViewLoad()
add the following:
在您的 ViewController 中didViewLoad()
添加以下内容:
let myView = DrawCircles(frame: CGRect(x: 50, y: 50, width: 300, height: 300))
self.view.addSubview(myView)
When it runs it should look like this. I hope you like my solution!
当它运行时,它应该是这样的。我希望你喜欢我的解决方案!