Como desenhar um UIView personalizado que é apenas um círculo - aplicativo para iPhone


129

Como eu desenharia um UIView personalizado que é literalmente apenas uma bola (um círculo 2D)? Gostaria apenas de substituir o método drawRect? E alguém pode me mostrar o código para desenhar um círculo azul?

Além disso, seria bom alterar o quadro dessa visão dentro da própria classe? Ou preciso alterar o quadro de uma classe diferente?

(apenas tentando montar uma bola quicando)

Respostas:


209

Você pode usar o QuartzCore e fazer algo assim -

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

104
FYI, para que sua visão seja um círculo usando o QuartCore, o raio do seu canto precisa ser metade da altura / largura do quadro. Essa é a maneira mais fácil de fazer um círculo, mas não é necessariamente a mais eficiente. Se o desempenho for vital, o drawRect provavelmente produzirá melhores resultados.
Benjamin Mayo

4
E isso é. 100 é a altura / largura.
Kal

3
Sim, desculpe, não estava direcionando isso para você, Kal. Eu mencionei isso para StanLe, caso ele quisesse usar visualizações de tamanhos diferentes.
Benjamin Mayo

Se o tamanho circleView não é 100X100, o cornerRadius deve ser o (tamanho novo) / 2
gran33

Mas notei que o círculo com raio de canto às vezes possui bordas ligeiramente "planas" / cortadas. Pelo menos quando usado com uma borda. Alguma idéia do porquê? O raio tem exatamente a metade do tamanho da visualização. Eu pensei que poderia ser um problema de recorte, mas não parece assim, tentei mesmo com uma subcamada menor - ainda tem o mesmo efeito.
Ixx

135

Gostaria apenas de substituir o método drawRect?

Sim:

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

Além disso, seria bom alterar o quadro dessa visão dentro da própria classe?

Idealmente não, mas você poderia.

Ou preciso alterar o quadro de uma classe diferente?

Eu deixaria o pai controlar isso.


1
Como definir cores personalizadas, não apenas o azul? Eu tento usar branco e azul como este: ([self.colorOfCircle CGColor]), mas nada acontece: \
gaussblurinc

@loldop is self.colorOfCircle um UIColor? Está definido? Se você colocar um ponto de interrupção nessa linha e observar o valor, é o que você está esperando? Se você definir isso após o fato, precisará invalidar a parte da sua visualização que contém o círculo.
Steve

9
uso @gaussblurinc CGContextSetFillColorWithColor(ctx, self.colorOfCircle.CGColor);, o método proposto na solução CGColorGetComponentssó funciona com algumas cores, consulte stackoverflow.com/questions/9238743/...
yonilevy

Nota para quem fica preso nisso. Em vez disso rect, usei acidentalmente self.framea elipse. O valor correto é self.bounds. D'oh! :)
Olie

31

Aqui está outra maneira de usar o UIBezierPath (talvez seja tarde demais ^^) Crie um círculo e oculte o UIView com ele, da seguinte maneira:

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;

1
Não é realmente necessário transformar essa forma de máscara em uma máscara; você pode usar a camada de forma diretamente como a camada da vista e dar uma cor de preenchimento. A máscara é provavelmente significativamente mais cara.
Jesse Rusak

A camada do UIView é CALayer, então como podemos desenhar uma forma nessa camada. Suponho que adicionamos camada de forma à camada de visualização sem mascará-la?
21714 Gintama

1
Você pode subclassificar o UIView e substituir o layerClassmétodo de classe para torná-lo uma camada de forma.
Jesse Rusak

@ JessieRusak, o problema que estou tendo com sua sugestão (para definir a forma na camada do UIView) é que você não pode usar corretamente o backgroundColor. Você precisaria aplicar um fillColor e definir o backgroundColor como clearColor, o que significa que um usuário do UIView não seria capaz de definir naturalmente o backgroundColor.
Richard Venable

25

Minha contribuição com uma extensão Swift:

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

Apenas ligue myView.asCircle()


definindo masksToBoundsa verdade e usando selfsão todos opcionais nesta resposta, mas ainda é a solução mais curto e melhor
Max Desiatov

17

Swift 3 - classe personalizada, fácil de reutilizar. Ele usa o backgroundColorconjunto no construtor de UI

import UIKit

@IBDesignable
class CircleBackgroundView: UIView {

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

}

1
Excelente. Essa é a abordagem correta e adaptativa.
Womble 17/06

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

6

Outra maneira de abordar o desenho em círculo (e outras formas) é usando máscaras. Você desenha círculos ou outras formas criando, primeiro, máscaras das formas necessárias; segundo, fornece quadrados de sua cor e, terceiro, aplica máscaras a esses quadrados de cor. Você pode alterar a máscara ou a cor para obter um novo círculo personalizado ou outra forma.

#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

Aqui está a saída do código acima:

quatro círculos


2

Há outra alternativa para pessoas preguiçosas. Você pode definir o layer.cornerRadius caminho da chave para sua visualização no Interface Builder . Por exemplo, se sua visualização tiver uma largura = altura de 48 , defina layer.cornerRadius = 24:

insira a descrição da imagem aqui

No entanto, isso só funciona se você tiver um tamanho estático da visualização (width/height is fixed)e não estiver mostrando o círculo no construtor de interfaces.


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        
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.