Cocoa Touch: ¿Cómo cambiar el grosor y el color del borde de UIView?

Respuestas:

596

Debe usar la capa de vista para establecer la propiedad del borde. p.ej:

#import <QuartzCore/QuartzCore.h>
...
view.layer.borderColor = [UIColor redColor].CGColor;
view.layer.borderWidth = 3.0f;

También debe vincular con QuartzCore.framework para acceder a esta funcionalidad.

Vladimir
fuente
¿Hay alguna forma de establecer diferentes anchos / colores para cada lado?
lluismontero
2
@lluismontero Me temo que tendrás que hacer UIView personalizado con drawRect: método para eso
Vladimir
1
Si hago esto, y además de esta vista, tengo una animación, como un UINavigationController modal descartando, veo que ocurren muchos fallos técnicos, es difícil de describir. Si desactivo las fronteras, todo vuelve a la normalidad.
Nicu Surdu
55
Solo un aviso para los demás. Xcode sugiere unir UIColor a CGColorRef como __bridge CGColorRef. Esto no funciona. Tiene que ser [UIColor blackColor].CGColorcomo se menciona en la respuesta.
GoodSp33d
66
#import <QuartzCore/QuartzCore.h>Ya no es necesario.
significado-asuntos
43

Actualización de Xcode 6

Desde la versión más nueva de Xcode hay una mejor solución para esto:

Con @IBInspectableusted puede establecer los atributos directamente desde dentro de la Attributes Inspector.

Mi vista personalizada @IBInspectable Attributes

Esto establece el User Defined Runtime Attributespara usted:

ingrese la descripción de la imagen aquí

Hay dos enfoques para configurar esto:

Opción 1 (con actualización en vivo en Storyboard)

  1. Crear MyCustomView.
  2. Esto hereda de UIView.
  3. Establecer @IBDesignable(esto hace que la actualización Ver sea activa). *
  4. Establezca sus atributos de tiempo de ejecución (borde, etc.) con @IBInspectable
  5. Cambia tu clase de vistas a MyCustomView
  6. Edite en el Panel de atributos y vea los cambios en Storyboard :)

``

@IBDesignable
class MyCustomView: UIView {
    @IBInspectable var cornerRadius: CGFloat = 0 {
        didSet {
            layer.cornerRadius = cornerRadius
            layer.masksToBounds = cornerRadius > 0
        }
    }
    @IBInspectable var borderWidth: CGFloat = 0 {
        didSet {
            layer.borderWidth = borderWidth
        }
    }
    @IBInspectable var borderColor: UIColor? {
        didSet {
            layer.borderColor = borderColor?.CGColor
        }
    }
}

* @IBDesignablesolo funciona cuando se establece al comienzo declass MyCustomView

Opción 2 (no funciona desde Swift 1.2, ver comentarios)

Extienda su clase UIView:

extension UIView {
    @IBInspectable var cornerRadius: CGFloat = 0 {
        didSet {
            layer.cornerRadius = cornerRadius
            layer.masksToBounds = cornerRadius > 0
        }
    }
    @IBInspectable var borderWidth: CGFloat = 0 {
        didSet {
            layer.borderWidth = borderWidth
        }
    }
    @IBInspectable var borderColor: UIColor? {
        didSet {
            layer.borderColor = borderColor?.CGColor
        }
    }
}

De esta manera, su Vista predeterminada siempre tiene esos campos editables adicionales Attributes Inspector. Otra ventaja es que no tiene que cambiar la clase MycustomViewcada vez. Sin embargo, un inconveniente de esto es que solo verá sus cambios cuando ejecute su aplicación.

MMachinegun
fuente
1
Su extensión no funciona en la última versión de Xcode a partir de hoy.
Edgar Aroutiounian
1
Confirmaré a @EdgarAroutiounian solo para decir que en Swift 1.2 el segundo enfoque ya no funciona
Sergey Grischyov,
¿Qué pasa con Objective-C?
Nik Kov
Mira la respuesta de spencery2 más abajo, se tomó el tiempo para escribirla en el Objetivo C:
MMachinegun
actualice la extensión para que no almacene un valor y use set (value) {} y obtenga {} para acceder a la capa directamente, entonces funciona.
LightningStryk
17

También puede crear un borde con el color de su deseo.

view.layer.borderColor = [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:1.0].CGColor;

* r, g, b son los valores entre 0 y 255.

rohan-patel
fuente
66
Vale la pena señalar eso r, gy bprobablemente debería ser flotadores; los divisores también deben ser flotadores: r / 255.0.
no, la sintaxis de C no es como dices. r, gyb pueden ser int, ya que las promociones C (y objC IS C) arrojarán int r = 128 al doble al hacer: r / 255.0. Por cierto, obtuviste el doble, y Clang lanzará a CGFloat.
ingconti
10

Agregue los siguientes @IBInspectables en la extensión UIView

extension UIView {

  @IBInspectable var borderWidth: CGFloat {
    get {
      return layer.borderWidth
    }
    set(newValue) {
      layer.borderWidth = newValue
    }
  }

  @IBInspectable var borderColor: UIColor? {
    get {
      if let color = layer.borderColor {
        return UIColor(CGColor: color)
      }
      return nil
    }
    set(newValue) {
      layer.borderColor = newValue?.CGColor
    }
  }
}

Y luego debería poder establecer los atributos borderColor y borderWidth directamente desde el inspector de atributos. Ver imagen adjunta

Inspector de atributos

Bikramjit Singh
fuente
8

Cuando uso la solución CALayer de Vladimir, y en la parte superior de la vista, tengo una animación, como un UINavigationController modal que se descarta, veo que ocurren muchos problemas técnicos y problemas de rendimiento de dibujo.

Entonces, otra forma de lograr esto, pero sin los problemas técnicos y la pérdida de rendimiento, es crear una UIView personalizada e implementar el drawRectmensaje de esta manera:

- (void)drawRect:(CGRect)rect
{
    CGContextRef contextRef = UIGraphicsGetCurrentContext();
    CGContextSetLineWidth(contextRef, 1);
    CGContextSetRGBStrokeColor(contextRef, 255.0, 255.0, 255.0, 1.0);
    CGContextStrokeRect(contextRef, rect);    
}
Nicu Surdu
fuente
@ Krish Usted almacena el color en una variable y cuando necesita cambiar el color del borde, cambia el valor de la variable y llama setNeedsDisplaya la vista. Esto obligará a volver a dibujar la UIView e implícitamente volverá a llamar drawRect. No probado, aunque ...
Nicu Surdu
8
view.layer.borderWidth = 1.0
view.layer.borderColor = UIColor.lightGray.cgColor
shaiju mathew
fuente
1
Realmente no me gusta que la gente sea rechazada sin una explicación. No ayuda a nadie.
David DelMonte
7

Prueba este código:

view.layer.borderColor =  [UIColor redColor].CGColor;
view.layer.borderWidth= 2.0;
[view setClipsToBounds:YES];
Vikram Biwal
fuente
4

No sugeriría anular el drawRect debido a que causa un impacto en el rendimiento.

En cambio, modificaría las propiedades de la clase como se muestra a continuación (en su uiview personalizado):

  - (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
      self.layer.borderWidth = 2.f;
      self.layer.borderColor = [UIColor redColor].CGColor;
    }
  return self;

No vi ningún problema técnico al tomar el enfoque anterior, no estoy seguro de por qué poner el initWithFrame detiene estos ;-)

DEzra
fuente
3

Quería agregar esto a la respuesta de @marczking ( Opción 1 ) como un comentario, pero mi bajo estado en StackOverflow lo impide.

Hice un puerto de la respuesta de @marczking al Objetivo C. Funciona de maravilla, ¡gracias @marczking!

UIView + Border.h:

#import <UIKit/UIKit.h>

IB_DESIGNABLE
@interface UIView (Border)

-(void)setBorderColor:(UIColor *)color;
-(void)setBorderWidth:(CGFloat)width;
-(void)setCornerRadius:(CGFloat)radius;

@end

UIView + Border.m:

#import "UIView+Border.h"

@implementation UIView (Border)
// Note: cannot use synthesize in a Category

-(void)setBorderColor:(UIColor *)color
{
    self.layer.borderColor = color.CGColor;
}

-(void)setBorderWidth:(CGFloat)width
{
    self.layer.borderWidth = width;
}

-(void)setCornerRadius:(CGFloat)radius
{
    self.layer.cornerRadius = radius;
    self.layer.masksToBounds = radius > 0;
}

@end
Spencery2
fuente
2

@IBInspectable me funciona en iOS 9, Swift 2.0

extension UIView {

@IBInspectable var borderWidth: CGFloat {
get {
        return layer.borderWidth
    }
    set(newValue) {
        layer.borderWidth = newValue
    }
}

@IBInspectable var cornerRadius: CGFloat {
    get {
        return layer.cornerRadius
    }
    set(newValue) {
        layer.cornerRadius = newValue
    }
}

@IBInspectable var borderColor: UIColor? {
    get {
        if let color = layer.borderColor {
            return UIColor(CGColor: color)
        }
        return nil
    }
    set(newValue) {
        layer.borderColor = newValue?.CGColor
    }
}
anhtran
fuente
1

Si no desea editar la capa de una UIView, siempre puede incrustar la vista dentro de otra vista. La vista principal tendría su color de fondo establecido en el color del borde. También sería un poco más grande, dependiendo de qué tan ancho desea que sea el borde.

Por supuesto, esto solo funciona si su vista no es transparente y solo desea un color de borde único. El OP quería el borde en la vista misma, pero esta puede ser una alternativa viable.

Matt Becker
fuente
0

Si desea agregar diferentes bordes en diferentes lados, puede agregar una subvista con el estilo específico, es una forma fácil de encontrar.

Yuanfei Zhu
fuente
0

color del borde del elemento en swift 4.2:

let cell = tableView.dequeueReusableCell(withIdentifier: "Cell_lastOrderId") as! Cell_lastOrder
cell.layer.borderWidth = 1
cell.layer.borderColor = UIColor.white.cgColor
cell.layer.cornerRadius = 10
Akhrua
fuente