web-dev-qa-db-fra.com

Comment dessiner un cercle dans iOS Swift?

let block = UIView(frame: CGRectMake(cellWidth-25, cellHeight/2-8, 16, 16))
block.backgroundColor = UIColor(netHex: 0xff3b30)
block.layer.cornerRadius = 9
block.clipsToBounds = true

C'est ce que j'ai pour le moment, mais ce n'est évidemment pas la bonne façon de le faire.

Quel est le moyen le plus simple de le faire?

60
TIMEX

Vous pouvez dessiner un cercle avec ceci:

Swift 2.2:

    let circlePath = UIBezierPath(arcCenter: CGPoint(x: 100,y: 100), radius: CGFloat(20), startAngle: CGFloat(0), endAngle:CGFloat(M_PI * 2), clockwise: true)

    let shapeLayer = CAShapeLayer()
    shapeLayer.path = circlePath.CGPath

    //change the fill color
    shapeLayer.fillColor = UIColor.clearColor().CGColor
    //you can change the stroke color
    shapeLayer.strokeColor = UIColor.redColor().CGColor
    //you can change the line width
    shapeLayer.lineWidth = 3.0

    view.layer.addSublayer(shapeLayer)

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)

Avec le code que vous avez posté, vous coupez les coins de UIView sans ajouter de cercle à la vue.


Voici un exemple complet d'utilisation de cette méthode:

// make the UIView a ring of color
import UIKit
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)
        }
    }

 enter image description here


Notez cependant qu'il y a un appel incroyablement pratique

let circlePath = UIBezierPath (ovalInRect: rect)

qui fait tout le travail de faire le chemin. (N'oubliez pas de l'insérer pour l'épaisseur du trait, ce qui est également incroyablement facile avec 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)
    }

 enter image description here


En pratique ces jours-ci à Swift, vous utiliseriez certainement

@IBDesignable

et

@IB Insspectable

De cette façon, vous pouvez réellement voir et modifier le rendu dans Storyboard!}

Comme vous pouvez le constater, l'inspecteur sur le storyboard est doté de nouvelles fonctionnalités que vous pouvez modifier sur le storyboard:

 enter image description here

Voici le code ...

// Dot with border, which you can control completely in Storyboard
import UIKit
@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)
        }
    }

Enfin, notez que si vous avez une vue UIView (qui est carrée et que vous voulez définir le rouge dans Storyboard) et que vous voulez simplement la transformer en cercle rouge, vous pouvez simplement procéder comme suit:

// It makes a UIView into a circular dot of color
import UIKit
class Dot:UIView
    {
    override func layoutSubviews()
        { layer.cornerRadius = bounds.size.width/2; }
    }
186
Dario

Si vous voulez utiliser UIView pour le dessiner, vous devez définir le rayon/de la hauteur ou de la largeur.

alors changez simplement:

block.layer.cornerRadius = 9

à:

block.layer.cornerRadius = block.frame.width / 2

Cependant, vous aurez besoin de rendre la hauteur et la largeur identiques. Si vous souhaitez utiliser coregraphics, vous voudrez faire quelque chose comme ceci:

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);
7
Oxcug

Créez une classe UIView et attribuez-lui ce code pour un simple cercle

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()


    }


}
3
MadProgrammer

Mise à jour de l'approche de code de @ Dario pour Xcode 8.2.2, Swift 3.x. Notez que dans le storyboard, définissez la couleur d'arrière-plan sur "clear" pour éviter un arrière-plan noir dans le carré 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)
    }
}

Et si vous voulez contrôler les angles de début et de fin:

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)
    }
}
3
Jacob Davis

Swift 4 version de la réponse acceptée:

@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)
    }
}
2
atereshkov

Je trouve que Core Graphics est assez simple pour Swift 3 :

if let cgcontext = UIGraphicsGetCurrentContext() {
    cgcontext.strokeEllipse(in: CGRect(x: center.x-diameter/2, y: center.y-diameter/2, width: diameter, height: diameter))
}
1
biomiker

Une approche beaucoup plus facile et conviviale serait.

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
    }

}

Avec Border Color et Border Size et la propriété par défaut Background, vous pouvez définir l'apparence du cercle. 

 enter image description here

Veuillez noter que pour dessiner un cercle, la hauteur et la largeur de la vue doivent être de taille égale. 

Le code fonctionne pour Swift >= 4 et Xcode >= 9

0
Paul Wasilewski

Ajouter dans la vue a chargé

    //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)
0
Ankit Kushwah

Une simple fonction dessinant un cercle au milieu du cadre de votre fenêtre, en utilisant un pourcentage de multiplicateur

/// 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)
}
0
tryp