Cómo dibujar una vista UIV personalizada que es solo un círculo - aplicación para iPhone

129

¿Cómo haría para dibujar un UIView personalizado que es literalmente solo una bola (un círculo 2D)? ¿Solo anularía el método drawRect? ¿Y alguien puede mostrarme el código para dibujar un círculo azul?

Además, ¿estaría bien cambiar el marco de esa vista dentro de la clase misma? ¿O necesito cambiar el marco de una clase diferente?

(solo tratando de configurar una pelota que rebota)

StanLe
fuente

Respuestas:

209

Podrías usar QuartzCore y hacer algo así:

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
fuente
104
Para su información, para que su vista sea un círculo usando QuartCore, su radio de esquina debe ser la mitad de la altura / ancho de su marco. Esta es la forma más fácil de hacer un círculo, pero no es necesariamente la más eficiente. Si el rendimiento es vital, drawRect probablemente producirá mejores resultados.
Benjamin Mayo
44
Y es. 100 es la altura / ancho.
Kal
3
Sí, lo siento, no te estaba dirigiendo eso, Kal. Se lo mencioné a StanLe en caso de que quisiera usar vistas de diferentes tamaños.
Benjamin Mayo
Si su tamaño circleView no es 100X100, el cornerRadius debería ser el (nuevo tamaño) / 2
gran33
Pero noté que el círculo con radio de esquina a veces tiene bordes ligeramente "planos" / recortados. Al menos cuando se usa con un borde. ¿Alguna idea de por qué? El radio es exactamente la mitad del tamaño de la vista. Pensé que podría ser un problema de recorte, pero no lo parece, incluso con una subcapa más pequeña, todavía tengo el mismo efecto.
Ixx
135

¿Solo anularía el método drawRect?

Si:

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

Además, ¿estaría bien cambiar el marco de esa vista dentro de la clase misma?

Idealmente no, pero podrías.

¿O necesito cambiar el marco de una clase diferente?

Dejo que los padres controlen eso.

Steve
fuente
1
¿Cómo puedo configurar colores personalizados, no solo azules? Intento usar blanco y azul como este: ([self.colorOfCircle CGColor]) pero no sucede nada: \
gaussblurinc
@loldop es self.colorOfCircle un UIColor? ¿Está listo? Si coloca un punto de interrupción en esa línea y observa el valor, ¿es lo que espera? Si configura eso después del hecho, tendrá que invalidar la parte de su vista que contiene el círculo.
Steve
9
@gaussblurinc uso CGContextSetFillColorWithColor(ctx, self.colorOfCircle.CGColor);, el método propuesto en la solución CGColorGetComponentssolo funciona con algunos colores, consulte stackoverflow.com/questions/9238743/…
yonilevy
Nota para cualquiera que se quede atrapado en esto. En lugar de recteso, accidentalmente lo usé self.framepara la elipse. El valor correcto es self.bounds. D'oh! :)
Olie
31

Aquí hay otra forma usando UIBezierPath (tal vez sea demasiado tarde ^^) Cree un círculo y enmascare UIView con él, de la siguiente manera:

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
fuente
1
Realmente no es necesario hacer de esa capa de forma una máscara; puedes usar la capa de forma directamente como la capa de la vista y darle un color de relleno. La máscara es probablemente significativamente más cara.
Jesse Rusak
La capa de UIView es CALayer, entonces, ¿cómo podemos dibujar una forma en esta capa? Supongo que agregamos una capa de forma a la capa de la vista sin enmascararla.
Gintama
1
Puede subclasificar UIView y anular el layerClassmétodo de clase para convertirlo en una capa de forma.
Jesse Rusak
@JesseRusak, el problema que tengo con tu sugerencia (para establecer la forma en la capa de UIView) es que no puedes usar correctamente el backgroundColor. Tendría que aplicar un fillColor y establecer backgroundColor en clearColor, lo que significa que un usuario de UIView no podrá establecer naturalmente backgroundColor.
Richard Venable
25

Mi contribución con una extensión Swift:

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

Solo llama myView.asCircle()

Kevin ABRIOUX
fuente
establecer masksToBoundsen verdadero y usar selfson todos opcionales en esta respuesta, pero sigue siendo la solución más corta y mejor
Max Desiatov
17

Swift 3 : clase personalizada, fácil de reutilizar. Utiliza backgroundColorset en el generador de IU

import UIKit

@IBDesignable
class CircleBackgroundView: UIView {

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

}
Maciej
fuente
1
Excelente. Este es el enfoque correcto y adaptativo.
Womble
14

Swift 3 clase:

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
fuente
6

Otra forma de acercarse al dibujo circular (y otras formas) es usando máscaras. Dibuja círculos u otras formas, primero, haciendo máscaras de las formas que necesita, segundo, proporciona cuadrados de su color y, tercero, aplica máscaras a esos cuadrados de color. Puede cambiar la máscara o el color para obtener un nuevo círculo personalizado u otra 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

Aquí está la salida del código anterior:

cuatro círculos

matrix3003
fuente
2

Hay otra alternativa para la gente perezosa. Puede establecer la layer.cornerRadius ruta clave para su vista en el Creador de interfaces . Por ejemplo, si su vista tiene un ancho = alto de 48 , establezca layer.cornerRadius = 24:

ingrese la descripción de la imagen aquí

Sin embargo, esto solo funciona si tiene un tamaño estático de la vista (width/height is fixed)y no muestra el círculo en el generador de interfaces.

usuario8675
fuente
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
fuente