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)

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

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.


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;

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


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
    }

}

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

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


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.


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        
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.