Comment dessiner un UIView personnalisé qui n'est qu'un cercle - Application iPhone

129

Comment puis-je dessiner un UIView personnalisé qui n'est littéralement qu'une balle (un cercle 2D)? Est-ce que je remplacerais simplement la méthode drawRect? Et quelqu'un peut-il me montrer le code pour dessiner un cercle bleu?

De plus, serait-il acceptable de changer le cadre de cette vue dans la classe elle-même? Ou dois-je changer le cadre d'une classe différente?

(essayant juste de mettre en place une balle qui rebondit)

StanLe
la source

Réponses:

209

Vous pouvez utiliser QuartzCore et faire quelque chose comme ça -

self.circleView = [[UIView alloc] initWithFrame:CGRectMake(10,20,100,100)];
self.circleView.alpha = 0.5;
self.circleView.layer.cornerRadius = 50;  // half the width/height
self.circleView.backgroundColor = [UIColor blueColor];
Kal
la source
104
Pour votre information, pour que votre vue soit un cercle en utilisant QuartCore, votre rayon de coin doit être la moitié de la hauteur / largeur de votre cadre. C'est la manière la plus simple de créer un cercle, mais ce n'est pas nécessairement la plus efficace. Si les performances sont vitales, drawRect donnera probablement de meilleurs résultats.
Benjamin Mayo
4
Et c'est. 100 est la hauteur / largeur.
Kal
3
Ouais, désolé de ne pas t'avoir dirigé ça, Kal. Je mentionnais cela à StanLe au cas où il voudrait utiliser des vues de tailles différentes.
Benjamin Mayo
Si la taille de votre cercleView n'est pas de 100X100, le cornerRadius doit être le (nouvelle taille) / 2
gran33
Mais j'ai remarqué que le cercle avec un rayon d'angle a parfois des bords légèrement «plats» / coupés. Au moins lorsqu'il est utilisé avec une bordure. Une idée pourquoi? Le rayon est exactement la moitié de la taille de la vue. Je pensais que c'était peut-être un problème d'écrêtage, mais cela ne semble pas être le cas, essayé même avec une sous-couche plus petite - toujours le même effet.
Ixx
135

Est-ce que je remplacerais simplement la méthode drawRect?

Oui:

- (void)drawRect:(CGRect)rect
{
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextAddEllipseInRect(ctx, rect);
    CGContextSetFillColor(ctx, CGColorGetComponents([[UIColor blueColor] CGColor]));
    CGContextFillPath(ctx);
}

De plus, serait-il acceptable de changer le cadre de cette vue dans la classe elle-même?

Idéalement non, mais vous pourriez.

Ou dois-je changer le cadre d'une classe différente?

Je laisserais le parent contrôler ça.

Steve
la source
1
Comment puis-je définir des couleurs personnalisées, pas seulement le bleu? J'essaye d'utiliser le blanc et le bleu comme ceci: ([self.colorOfCircle CGColor]) mais rien ne se passe: \
gaussblurinc
@loldop est-ce que self.colorOfCircle est un UIColor? Est-ce défini? Si vous mettez un point d'arrêt sur cette ligne et regardez la valeur, est-ce ce que vous attendez? SI vous définissez cela après coup, vous devrez invalider la partie de votre vue qui contient le cercle.
Steve
9
@gaussblurinc use CGContextSetFillColorWithColor(ctx, self.colorOfCircle.CGColor);, la méthode proposée dans la solution CGColorGetComponentsne fonctionne qu'avec certaines couleurs, voir stackoverflow.com/questions/9238743/…
yonilevy
Note à tous ceux qui se retrouvent coincés là-dessus. Plutôt que rect, j'ai accidentellement utilisé self.framepour l'ellipse. La valeur correcte est self.bounds. Oh! :)
Olie
31

Voici une autre façon d'utiliser UIBezierPath (peut-être que c'est trop tard ^^) Créez un cercle et masquez UIView avec, comme suit:

UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
view.backgroundColor = [UIColor blueColor];

CAShapeLayer *shape = [CAShapeLayer layer];
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:view.center radius:(view.bounds.size.width / 2) startAngle:0 endAngle:(2 * M_PI) clockwise:YES];
shape.path = path.CGPath;
view.layer.mask = shape;
Gintama
la source
1
Il n'est pas vraiment nécessaire de faire de ce calque de forme un masque; vous pouvez simplement utiliser le calque de forme directement comme calque de la vue et lui donner une couleur de remplissage. Le masque est probablement beaucoup plus cher.
Jesse Rusak
Le calque d'UIView est CALayer alors comment pouvons-nous dessiner une forme sur ce calque. Je suppose que nous ajoutons un calque de forme au calque de la vue sans le masquer ??
Gintama
1
Vous pouvez sous-classer UIView et remplacer la layerClassméthode de classe pour en faire un calque de forme.
Jesse Rusak
@JesseRusak, le problème que j'ai avec votre suggestion (pour définir la forme sur le calque de UIView lui-même) est que vous ne pouvez pas utiliser correctement backgroundColor. Vous devrez appliquer un fillColor et définir backgroundColor sur clearColor, ce qui signifie qu'un utilisateur de UIView ne serait pas en mesure de définir naturellement backgroundColor.
Richard Venable
25

Ma contribution avec une extension Swift:

extension UIView {
    func asCircle() {
        self.layer.cornerRadius = self.frame.width / 2;
        self.layer.masksToBounds = true
    }
}

Il suffit d'appeler myView.asCircle()

Kevin ABRIOUX
la source
le réglage masksToBoundssur true et l'utilisation selfsont tous facultatifs dans cette réponse, mais c'est toujours la solution la plus courte et la meilleure
Max Desiatov
17

Swift 3 - classe personnalisée, facile à réutiliser. Il utilise un backgroundColorensemble dans le générateur d'interface utilisateur

import UIKit

@IBDesignable
class CircleBackgroundView: UIView {

    override func layoutSubviews() {
        super.layoutSubviews()
        layer.cornerRadius = bounds.size.width / 2
        layer.masksToBounds = true
    }

}
Maciej
la source
1
Excellent. C'est la bonne approche adaptative.
Womble
14

Classe Swift 3 :

import UIKit

class CircleView: UIView {

    override func draw(_ rect: CGRect) {
        guard let context = UIGraphicsGetCurrentContext() else {return}

        context.addEllipse(in: rect)
        context.setFillColor(.blue.cgColor)
        context.fillPath()
    }           
}
Vyacheslav
la source
6

Une autre façon d'aborder le dessin de cercle (et d'autres formes) consiste à utiliser des masques. Vous dessinez des cercles ou d'autres formes en créant d'abord des masques des formes dont vous avez besoin, en second lieu, en fournissant des carrés de votre couleur et, troisièmement, en appliquant des masques à ces carrés de couleur. Vous pouvez modifier le masque ou la couleur pour obtenir un nouveau cercle personnalisé ou une autre forme.

#import <QuartzCore/QuartzCore.h>

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIView *area1;
@property (weak, nonatomic) IBOutlet UIView *area2;
@property (weak, nonatomic) IBOutlet UIView *area3;
@property (weak, nonatomic) IBOutlet UIView *area4;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.area1.backgroundColor = [UIColor blueColor];
    [self useMaskFor: self.area1];

    self.area2.backgroundColor = [UIColor orangeColor];
    [self useMaskFor: self.area2];

    self.area3.backgroundColor = [UIColor colorWithRed: 1.0 green: 0.0 blue: 0.5 alpha:1.0];
    [self useMaskFor: self.area3];

    self.area4.backgroundColor = [UIColor colorWithRed: 1.0 green: 0.0 blue: 0.5 alpha:0.5];
    [self useMaskFor: self.area4];        
}

- (void)useMaskFor: (UIView *)colorArea {        
    CALayer *maskLayer = [CALayer layer];
    maskLayer.frame = colorArea.bounds;
    UIImage *maskImage = [UIImage imageNamed:@"cirMask.png"];
    maskLayer.contents = (__bridge id)maskImage.CGImage;
    colorArea.layer.mask = maskLayer;
}

@end

Voici la sortie du code ci-dessus:

quatre cercles

matrice3003
la source
2

Il existe une autre alternative pour les paresseux. Vous pouvez définir le layer.cornerRadius chemin d' accès clé de votre vue dans Interface Builder . Par exemple, si votre vue a une largeur = hauteur de 48 , définissez layer.cornerRadius = 24:

entrez la description de l'image ici

Cependant, cela ne fonctionne que si vous avez une taille statique de la vue (width/height is fixed)et que le cercle n'apparaît pas dans le générateur d'interface.

user8675
la source
1

Swift 3 - Xcode 8.1

@IBOutlet weak var myView: UIView!

override func viewDidLoad() {
    super.viewDidLoad() 

    let size:CGFloat = 35.0
    myView.bounds = CGRect(x: 0, y: 0, width: size, height: size)
    myView.layer.cornerRadius = size / 2
    myView.layer.borderWidth = 1
    myView.layer.borderColor = UIColor.Gray.cgColor        
}
Mohammad Razipour
la source