Cocoa Touch: Comment changer la couleur et l'épaisseur des bordures d'UIView?

Réponses:

596

Vous devez utiliser le calque de la vue pour définir la propriété de la bordure. par exemple:

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

Vous devez également vous connecter à QuartzCore.framework pour accéder à cette fonctionnalité.

Vladimir
la source
Existe-t-il un moyen de définir des largeurs / couleurs différentes pour chaque côté?
lluismontero
2
@lluismontero J'ai peur que vous deviez créer une UIView personnalisée avec drawRect: méthode pour cela
Vladimir
1
Si je fais cela, et en plus de cette vue, j'ai une animation, comme un UINavigationController modal qui se ferme, je vois beaucoup de problèmes se produire, c'est difficile à décrire. Si je désactive les frontières, tout redevient normal.
Nicu Surdu
5
Juste un avertissement pour les autres. Xcode suggère de relier UIColor à CGColorRef en tant que __bridge CGColorRef. Cela ne fonctionne pas. Il doit être [UIColor blackColor].CGColorcomme mentionné dans la réponse.
GoodSp33d
6
#import <QuartzCore/QuartzCore.h>n'est plus nécessaire.
signification est importante
43

Mise à jour Xcode 6

Depuis la dernière version de Xcode, il existe une meilleure solution:

Avec @IBInspectablevous pouvez définir des attributs directement à partir de l' intérieur du Attributes Inspector.

Ma vue personnalisée @IBInspectable Attributes

Cela définit le User Defined Runtime Attributespour vous:

entrez la description de l'image ici

Il existe deux approches pour configurer cela:

Option 1 (avec mise à jour en direct dans Storyboard)

  1. Créez MyCustomView.
  2. Cela hérite de UIView.
  3. Set @IBDesignable(cela rend la mise à jour de View en direct). *
  4. Définissez vos attributs d'exécution (bordure, etc.) avec @IBInspectable
  5. Changez votre classe de vues en MyCustomView
  6. Modifier dans le panneau d'attributs et voir les changements dans 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
        }
    }
}

* @IBDesignablene fonctionne que lorsqu'il est défini au début declass MyCustomView

Option 2 (ne fonctionne pas depuis Swift 1.2, voir les commentaires)

Étendez votre classe 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 cette façon, votre vue par défaut contient toujours ces champs modifiables supplémentaires Attributes Inspector. Un autre avantage est que vous n'avez pas à changer la classe à MycustomViewchaque fois. Cependant, un inconvénient est que vous ne verrez vos modifications que lorsque vous exécutez votre application.

MMachinegun
la source
1
Votre extension ne fonctionne pas dans la dernière version de Xcode à partir d'aujourd'hui.
Edgar Aroutiounian
1
Je confirmerai @EdgarAroutiounian seulement pour dire que dans Swift 1.2 la deuxième approche ne fonctionne plus
Sergey Grischyov
Et Objective-C?
Nik Kov
Découvrez la réponse de spencery2 ci-dessous, il a pris le temps de l'écrire dans Objective-C:
MMachinegun
mettre à jour l'extension pour ne pas stocker de valeur et utiliser set (value) {} et obtenir {} pour accéder directement à la couche, cela fonctionne alors.
LightningStryk
17

Vous pouvez également créer une bordure avec la couleur de votre souhait.

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

* r, g, b sont les valeurs comprises entre 0 et 255.

rohan-patel
la source
6
Il convient de noter cela r, get bdevrait probablement être des flotteurs; les diviseurs doivent également être flotteurs: r / 255.0.
non, la syntaxe C n'est pas comme vous le dites. r, g et b peuvent être int, car les promotions C (et objC IS C) jetteront int r = 128 pour doubler lors de la création: r / 255.0. Soit dit en passant, vous avez doublé, et Clang va lancer sur CGFloat.
ingconti
10

Ajouter les @IBInspectables suivants dans l'extension 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
    }
  }
}

Et puis, vous devriez pouvoir définir les attributs borderColor et borderWidth directement à partir de l'inspecteur d'attributs. Voir l'image ci-jointe

Inspecteur d'attributs

Bikramjit Singh
la source
8

Lorsque j'utilise la solution CALayer de Vladimir, et en plus de la vue, j'ai une animation, comme le rejet d'un modulaire UINavigationController, je vois beaucoup de problèmes se produire et avoir des problèmes de performances de dessin.

Donc, une autre façon d'y parvenir, mais sans les problèmes et la perte de performances, est de créer une UIView personnalisée et d'implémenter le drawRectmessage comme suit :

- (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
la source
@Krish Vous stockez la couleur dans une variable et lorsque vous devez changer la couleur de la bordure, vous changez la valeur de la variable et appelez setNeedsDisplayla vue. Cela forcera le redessin de l'UIView et implicitement sera rappelé drawRect. Non testé, mais ...
Nicu Surdu
8
view.layer.borderWidth = 1.0
view.layer.borderColor = UIColor.lightGray.cgColor
shaiju mathew
la source
1
Je n'aime vraiment pas que les gens soient votés sans explication. Cela n'aide personne.
David DelMonte
7

Essayez ce code:

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

Je ne suggérerais pas de remplacer le drawRect en raison d'un impact sur les performances.

Au lieu de cela, je modifierais les propriétés de la classe comme ci-dessous (dans votre uiview personnalisé):

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

Je n'ai vu aucun problème lors de l'approche ci-dessus - je ne sais pas pourquoi la mise en initWithFrame arrête ces ;-)

DEzra
la source
3

Je voulais ajouter ceci à la réponse de @ marczking ( Option 1 ) en tant que commentaire, mais mon statut modeste sur StackOverflow l'empêche.

J'ai fait un portage de la réponse de @ marczking à l'objectif C. Fonctionne comme un charme, merci @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
la source
2

@IBInspectable fonctionne pour moi sur 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
la source
1

Si vous ne souhaitez pas modifier le calque d'une vue UIV, vous pouvez toujours incorporer la vue dans une autre vue. La couleur parent aurait sa couleur d'arrière-plan définie sur la couleur de la bordure. Il serait également légèrement plus grand, selon la largeur souhaitée de la bordure.

Bien sûr, cela ne fonctionne que si votre vue n'est pas transparente et que vous ne souhaitez qu'une seule couleur de bordure. Le PO voulait la frontière dans la vue elle-même, mais cela peut être une alternative viable.

Matt Becker
la source
0

Si vous souhaitez ajouter une bordure différente sur différents côtés, il peut être facile d'ajouter une sous-vue avec le style spécifique.

Yuanfei Zhu
la source
0

couleur de bordure de l'article dans 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
la source