Ma question concerne le titre.
Je ne sais pas comment ajouter une bordure dans un côté spécifique, en haut ou en bas, aucun côté ..layer.border
dessine la bordure pour la vue entière ...
Je considère le sous-classement UIView
et la substitution de drawRect
overkill ici. Pourquoi ne pas ajouter une extension sur UIView
et ajouter des sous-vues de bordure?
@discardableResult
func addBorders(edges: UIRectEdge,
color: UIColor,
inset: CGFloat = 0.0,
thickness: CGFloat = 1.0) -> [UIView] {
var borders = [UIView]()
@discardableResult
func addBorder(formats: String...) -> UIView {
let border = UIView(frame: .zero)
border.backgroundColor = color
border.translatesAutoresizingMaskIntoConstraints = false
addSubview(border)
addConstraints(formats.flatMap {
NSLayoutConstraint.constraints(withVisualFormat: $0,
options: [],
metrics: ["inset": inset, "thickness": thickness],
views: ["border": border]) })
borders.append(border)
return border
}
if edges.contains(.top) || edges.contains(.all) {
addBorder(formats: "V:|-0-[border(==thickness)]", "H:|-inset-[border]-inset-|")
}
if edges.contains(.bottom) || edges.contains(.all) {
addBorder(formats: "V:[border(==thickness)]-0-|", "H:|-inset-[border]-inset-|")
}
if edges.contains(.left) || edges.contains(.all) {
addBorder(formats: "V:|-inset-[border]-inset-|", "H:|-0-[border(==thickness)]")
}
if edges.contains(.right) || edges.contains(.all) {
addBorder(formats: "V:|-inset-[border]-inset-|", "H:[border(==thickness)]-0-|")
}
return borders
}
// Usage:
view.addBorder(edges: [.all]) // All with default arguments
view.addBorder(edges: [.top], color: .green) // Just Top, green, default thickness
view.addBorder(edges: [.left, .right, .bottom], color: .red, thickness: 3) // All except Top, red, thickness 3
Avec ce code, vous n'êtes pas non plus lié à votre sous-classe, vous pouvez l'appliquer à tout ce qui hérite de UIView
- réutilisable dans votre projet et dans d'autres. Transmettez d'autres arguments à vos méthodes pour définir d'autres couleurs et largeurs. De nombreuses options.
Version rapide de l'addition fantastique du 5/5/15 d'Adam Waite :
extension CALayer {
func addBorder(Edge: UIRectEdge, color: UIColor, thickness: CGFloat) {
var border = CALayer()
switch Edge {
case .Top:
border.frame = CGRectMake(0, 0, CGRectGetWidth(self.frame), thickness)
break
case .Bottom:
border.frame = CGRectMake(0, CGRectGetHeight(self.frame) - thickness, CGRectGetWidth(self.frame), thickness)
break
case .Left:
border.frame = CGRectMake(0, 0, thickness, CGRectGetHeight(self.frame))
break
case .Right:
border.frame = CGRectMake(CGRectGetWidth(self.frame) - thickness, 0, thickness, CGRectGetHeight(self.frame))
break
default:
break
}
border.backgroundColor = color.CGColor;
addSublayer(border)
}
}
Swift 3:
extension CALayer {
func addBorder(Edge: UIRectEdge, color: UIColor, thickness: CGFloat) {
let border = CALayer()
switch Edge {
case .top:
border.frame = CGRect(x: 0, y: 0, width: frame.width, height: thickness)
case .bottom:
border.frame = CGRect(x: 0, y: frame.height - thickness, width: frame.width, height: thickness)
case .left:
border.frame = CGRect(x: 0, y: 0, width: thickness, height: frame.height)
case .right:
border.frame = CGRect(x: frame.width - thickness, y: 0, width: thickness, height: frame.height)
default:
break
}
border.backgroundColor = color.cgColor;
addSublayer(border)
}
}
Le meilleur moyen pour moi est une catégorie sur UIView, mais en ajoutant des vues au lieu de CALayers, nous pouvons donc tirer parti d'AutoresizingMasks pour nous assurer que les bordures sont redimensionnées en même temps que la vue d'ensemble.
- (void)addTopBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth {
UIView *border = [UIView new];
border.backgroundColor = color;
[border setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin];
border.frame = CGRectMake(0, 0, self.frame.size.width, borderWidth);
[self addSubview:border];
}
- (void)addBottomBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth {
UIView *border = [UIView new];
border.backgroundColor = color;
[border setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin];
border.frame = CGRectMake(0, self.frame.size.height - borderWidth, self.frame.size.width, borderWidth);
[self addSubview:border];
}
- (void)addLeftBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth {
UIView *border = [UIView new];
border.backgroundColor = color;
border.frame = CGRectMake(0, 0, borderWidth, self.frame.size.height);
[border setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleRightMargin];
[self addSubview:border];
}
- (void)addRightBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth {
UIView *border = [UIView new];
border.backgroundColor = color;
[border setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin];
border.frame = CGRectMake(self.frame.size.width - borderWidth, 0, borderWidth, self.frame.size.height);
[self addSubview:border];
}
Swift 3.0
Swift 4.1
extension CALayer {
func addBorder(Edge: UIRectEdge, color: UIColor, thickness: CGFloat) {
let border = CALayer();
switch Edge {
case UIRectEdge.top:
border.frame = CGRect(x: 0, y: 0, width: self.frame.width, height: thickness)
break
case UIRectEdge.bottom:
border.frame = CGRect(x:0, y:self.frame.height - thickness, width:self.frame.width, height:thickness)
break
case UIRectEdge.left:
border.frame = CGRect(x:0, y:0, width: thickness, height: self.frame.height)
break
case UIRectEdge.right:
border.frame = CGRect(x:self.frame.width - thickness, y: 0, width: thickness, height:self.frame.height)
break
default:
break
}
border.backgroundColor = color.cgColor;
self.addSublayer(border)
}
}
Sous-classe UIView
et implémentez drawRect:
dans votre sous-classe, par exemple:
Objectif c
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextMoveToPoint(context, CGRectGetMinX(rect), CGRectGetMinY(rect));
CGContextAddLineToPoint(context, CGRectGetMaxX(rect), CGRectGetMinY(rect));
CGContextSetStrokeColorWithColor(context, [[UIColor redColor] CGColor] );
CGContextSetLineWidth(context, 2.0);
CGContextStrokePath(context);
}
Swift 4
override func draw(_ rect: CGRect) {
let cgContext = UIGraphicsGetCurrentContext()
cgContext?.move(to: CGPoint(x: rect.minX, y: rect.minY))
cgContext?.addLine(to: CGPoint(x: rect.maxX, y: rect.minY))
cgContext?.setStrokeColor(UIColor.red.cgColor)
cgContext?.setLineWidth(2.0)
cgContext?.strokePath()
}
Cela dessine une ligne rouge de 2 pixels en tant que bordure supérieure. Toutes les autres variations que vous mentionnez restent un exercice trivial pour le lecteur.
Guide de programmation Quartz 2D est recommandé.
Code pour la réponse sélectionnée, au cas où quelqu'un le voudrait.
REMARQUE: cela ne fonctionne pas avec l'autolayout (aka, faire pivoter un appareil en mode paysage, etc.).
Définissez d'abord une épaisseur:
NSInteger borderThickness = 1;
Il vous suffit ensuite de copier, d’utiliser tout ou partie de ces éléments pour définir la bordure que vous souhaitez définir.
Bordure supérieure
UIView *topBorder = [UIView new];
topBorder.backgroundColor = [UIColor lightGrayColor];
topBorder.frame = CGRectMake(0, 0, myView.frame.size.width, borderThickness);
[myView addSubview:topBorder];
Bordure inférieure
UIView *bottomBorder = [UIView new];
bottomBorder.backgroundColor = [UIColor lightGrayColor];
bottomBorder.frame = CGRectMake(0, myView.frame.size.height - borderThickness, myView.frame.size.width, borderThickness);
[myView addSubview:bottomBorder];
Frontière gauche
UIView *leftBorder = [UIView new];
leftBorder.backgroundColor = [UIColor lightGrayColor];
leftBorder.frame = CGRectMake(0, 0, borderThickness, myView.frame.size.height);
[myView addSubview:leftBorder];
Frontière droite
UIView *rightBorder = [UIView new];
rightBorder.backgroundColor = [UIColor lightGrayColor];
rightBorder.frame = CGRectMake(myView.frame.size.width - borderThickness, 0, borderThickness, myView.frame.size.height);
[myView addSubview:rightBorder];
Version rapide:
var myView = UIView(frame: CGRect(x: 100, y: 100, width: 100, height: 100))
myView.backgroundColor = UIColor.yellowColor()
var border = CALayer()
border.backgroundColor = UIColor.lightGrayColor()
border.frame = CGRect(x: 0, y: 0, width: myView.frame.width, height: 0.5)
myView.layer.addSublayer(border)
Edit: pour les versions mises à jour, consultez mon dépôt ici: https://github.com/goktugyil/EZSwiftExtensions/blob/master/Sources/UIViewExtensions.Swift
Regardez les pièces addBorder
Ancienne question, mais la solution autolayout avec ajustements de la frontière d'exécution toujours manquants.
borders(for: [.left, .bottom], width: 2, color: .red)
L'extension UIView suivante ajoutera la bordure uniquement sur les arêtes données. Si vous modifiez les arêtes à l'exécution, les bordures seront ajustées en conséquence.
extension UIView {
func borders(for edges:[UIRectEdge], width:CGFloat = 1, color: UIColor = .black) {
if edges.contains(.all) {
layer.borderWidth = width
layer.borderColor = color.cgColor
} else {
let allSpecificBorders:[UIRectEdge] = [.top, .bottom, .left, .right]
for Edge in allSpecificBorders {
if let v = viewWithTag(Int(Edge.rawValue)) {
v.removeFromSuperview()
}
if edges.contains(Edge) {
let v = UIView()
v.tag = Int(Edge.rawValue)
v.backgroundColor = color
v.translatesAutoresizingMaskIntoConstraints = false
addSubview(v)
var horizontalVisualFormat = "H:"
var verticalVisualFormat = "V:"
switch Edge {
case UIRectEdge.bottom:
horizontalVisualFormat += "|-(0)-[v]-(0)-|"
verticalVisualFormat += "[v(\(width))]-(0)-|"
case UIRectEdge.top:
horizontalVisualFormat += "|-(0)-[v]-(0)-|"
verticalVisualFormat += "|-(0)-[v(\(width))]"
case UIRectEdge.left:
horizontalVisualFormat += "|-(0)-[v(\(width))]"
verticalVisualFormat += "|-(0)-[v]-(0)-|"
case UIRectEdge.right:
horizontalVisualFormat += "[v(\(width))]-(0)-|"
verticalVisualFormat += "|-(0)-[v]-(0)-|"
default:
break
}
self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: horizontalVisualFormat, options: .directionLeadingToTrailing, metrics: nil, views: ["v": v]))
self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: verticalVisualFormat, options: .directionLeadingToTrailing, metrics: nil, views: ["v": v]))
}
}
}
}
}
// MARK: - Ajouter LeftBorder For View
(void)prefix_addLeftBorder:(UIView *) viewName
{
CALayer *leftBorder = [CALayer layer];
leftBorder.backgroundColor = [UIColor colorWithRed:221/255.0f green:221/255.0f blue:221/255.0f alpha:1.0f].CGColor;
leftBorder.frame = CGRectMake(0,0,1.0,viewName.frame.size.height);
[viewName.layer addSublayer:leftBorder];
}
// MARK: - Ajouter RightBorder For View
(void)prefix_addRightBorder:(UIView *) viewName
{
CALayer *rightBorder = [CALayer layer];
rightBorder.backgroundColor = [UIColor colorWithRed:221/255.0f green:221/255.0f blue:221/255.0f alpha:1.0f].CGColor;
rightBorder.frame = CGRectMake(viewName.frame.size.width - 1.0,0,1.0,viewName.frame.size.height);
[viewName.layer addSublayer:rightBorder];
}
// MARK: - Ajouter une bordure inférieure pour la vue
(void)prefix_addbottomBorder:(UIView *) viewName
{
CALayer *bottomBorder = [CALayer layer];
bottomBorder.backgroundColor = [UIColor colorWithRed:221/255.0f green:221/255.0f blue:221/255.0f alpha:1.0f].CGColor;
bottomBorder.frame = CGRectMake(0,viewName.frame.size.height - 1.0,viewName.frame.size.width,1.0);
[viewName.layer addSublayer:bottomBorder];
}
J'ai pris les réponses d'Adam Waite et de Paul et je les ai combinées. J'ai également ajouté la possibilité de relier les arêtes sélectionnées, vous n'avez donc qu'à appeler une seule fonction, comme ceci:
[self.view addBordersToEdge:(UIRectEdgeLeft|UIRectEdgeRight)
withColor:[UIColor grayColor]
andWidth:1.0];
ou alors:
[self.view addBordersToEdge:(UIRectEdgeAll)
withColor:[UIColor grayColor]
andWidth:1.0];
Ce que vous devez implémenter est une catégorie sur UIView comme suggéré dans d'autres réponses avec l'implémentation suivante:
- (void)addBordersToEdge:(UIRectEdge)Edge withColor:(UIColor *)color andWidth:(CGFloat) borderWidth {
if (Edge & UIRectEdgeTop) {
UIView *border = [UIView new];
border.backgroundColor = color;
[border setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin];
border.frame = CGRectMake(0, 0, self.frame.size.width, borderWidth);
[self addSubview:border];
}
if (Edge & UIRectEdgeLeft) {
UIView *border = [UIView new];
border.backgroundColor = color;
border.frame = CGRectMake(0, 0, borderWidth, self.frame.size.height);
[border setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleRightMargin];
[self addSubview:border];
}
if (Edge & UIRectEdgeBottom) {
UIView *border = [UIView new];
border.backgroundColor = color;
[border setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin];
border.frame = CGRectMake(0, self.frame.size.height - borderWidth, self.frame.size.width, borderWidth);
[self addSubview:border];
}
if (Edge & UIRectEdgeRight) {
UIView *border = [UIView new];
border.backgroundColor = color;
[border setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin];
border.frame = CGRectMake(self.frame.size.width - borderWidth, 0, borderWidth, self.frame.size.height);
[self addSubview:border];
}
}
Voici une solution simple. Ajoutez une étiquette sur votre UIView
, effacez le texte sur l'étiquette et définissez la couleur d'arrière-plan de l'étiquette sur votre couleur de bordure. Définissez le (x,y)
d'origine de votre étiquette sur le (x,y)
d'origine de votre vue. et définissez la largeur de l'étiquette sur la largeur de votre UIView
, définissez la hauteur sur 1 ou 2 (pour la hauteur de la bordure au sommet de votre UIView
). Et cela devrait faire l'affaire.
J'ai apporté quelques modifications à la réponse de Dan afin de pouvoir ajouter des bordures à plusieurs arêtes avec une seule commande:
infoView.addBorder(toEdges: [.left, .bottom, .right], color: borderColor, thickness: 1)
Voici le code complet:
extension UIView {
func addBorder(toEdges edges: UIRectEdge, color: UIColor, thickness: CGFloat) {
func addBorder(toEdge edges: UIRectEdge, color: UIColor, thickness: CGFloat) {
let border = CALayer()
border.backgroundColor = color.cgColor
switch edges {
case .top:
border.frame = CGRect(x: 0, y: 0, width: frame.width, height: thickness)
case .bottom:
border.frame = CGRect(x: 0, y: frame.height - thickness, width: frame.width, height: thickness)
case .left:
border.frame = CGRect(x: 0, y: 0, width: thickness, height: frame.height)
case .right:
border.frame = CGRect(x: frame.width - thickness, y: 0, width: thickness, height: frame.height)
default:
break
}
layer.addSublayer(border)
}
if edges.contains(.top) || edges.contains(.all) {
addBorder(toEdge: .top, color: color, thickness: thickness)
}
if edges.contains(.bottom) || edges.contains(.all) {
addBorder(toEdge: .bottom, color: color, thickness: thickness)
}
if edges.contains(.left) || edges.contains(.all) {
addBorder(toEdge: .left, color: color, thickness: thickness)
}
if edges.contains(.right) || edges.contains(.all) {
addBorder(toEdge: .right, color: color, thickness: thickness)
}
}
}
Swift 4.2 et AutoLayout
J'ai parcouru les solutions proposées. Beaucoup sont basés sur des cadres. Il s’agit d’une simple extension fonctionnant avec AutoLayout. Utilisez View au lieu de Layer pour vous assurer que vous pouvez utiliser AutoLayout - Sous-vue unique avec 4 contraintes.
Utilisez comme suit:
self.addBorder(.bottom, color: .lightGray, thickness: 0.5)
extension UIView {
func addBorder(_ Edge: UIRectEdge, color: UIColor, thickness: CGFloat) {
let subview = UIView()
subview.translatesAutoresizingMaskIntoConstraints = false
subview.backgroundColor = color
self.addSubview(subview)
switch Edge {
case .top, .bottom:
subview.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 0).isActive = true
subview.rightAnchor.constraint(equalTo: self.rightAnchor, constant: 0).isActive = true
subview.heightAnchor.constraint(equalToConstant: thickness).isActive = true
if Edge == .top {
subview.topAnchor.constraint(equalTo: self.topAnchor, constant: 0).isActive = true
} else {
subview.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 0).isActive = true
}
case .left, .right:
subview.topAnchor.constraint(equalTo: self.topAnchor, constant: 0).isActive = true
subview.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 0).isActive = true
subview.widthAnchor.constraint(equalToConstant: thickness).isActive = true
if Edge == .left {
subview.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 0).isActive = true
} else {
subview.rightAnchor.constraint(equalTo: self.rightAnchor, constant: 0).isActive = true
}
default:
break
}
}
}
Ma réponse à une question similaire: https://stackoverflow.com/a/27141956/435766 Personnellement, je préfère aller dans la catégorie route pour celle-là, car je veux pouvoir l'utiliser sous-classe de UIView.
En me basant sur la réponse de NSBum , j'ai adopté une approche similaire et créé cette sous-classe UIView simple afin qu'elle fonctionne dans Interface Builder et avec des contraintes: github link
En utilisant CGContextFillRect au lieu de CGContextStrokePath, j'ai pu, de manière prévisible, maintenir les lignes complètement solides et dans les limites de la vue.
Voici mon article de blog à ce sujet: http://natrosoft.com/?p=55
- En gros, déposez UIView dans Interface Builder et changez son type de classe en NAUIViewWithBorders.
-- Ensuite, dans le viewDidLoad de votre VC, procédez comme suit:
/* For a top border only ———————————————- */
self.myBorderView.borderColorTop = [UIColor redColor];
self.myBorderView..borderWidthsAll = 1.0f;
/* For borders with different colors and widths ————————— */
self.myBorderView.borderWidths = UIEdgeInsetsMake(2.0, 4.0, 6.0, 8.0);
self.myBorderView.borderColorTop = [UIColor blueColor];
self.myBorderView.borderColorRight = [UIColor redColor];
self.myBorderView.borderColorBottom = [UIColor greenColor];
self.myBorderView.borderColorLeft = [UIColor darkGrayColor];
Voici un lien direct vers le fichier .m afin que vous puissiez voir la mise en œuvre . Il existe également un projet de démonstration. J'espère que ça aide quelqu'un :)
Il suffit de poster ici pour aider quelqu'un qui cherche à ajouter des frontières. J'ai apporté quelques modifications à la réponse acceptée ici étiquette Swift uniquement bordure gauche . Largeur modifiée dans le cas UIRectEdge.Top
de CGRectGetHeight(self.frame)
à CGRectGetWidth(self.frame)
et dans le cas UIRectEdge.Bottom
de UIScreen.mainScreen().bounds.width
à CGRectGetWidth(self.frame)
pour obtenir les bordures correctement. Utilisation de Swift 2.
Enfin l'extension est:
extension CALayer {
func addBorder(Edge: UIRectEdge, color: UIColor, thickness: CGFloat) {
let border = CALayer();
switch Edge {
case UIRectEdge.Top:
border.frame = CGRectMake(0, 0, CGRectGetWidth(self.frame), thickness);
break
case UIRectEdge.Bottom:
border.frame = CGRectMake(0, CGRectGetHeight(self.frame) - thickness, CGRectGetWidth(self.frame), thickness)
break
case UIRectEdge.Left:
border.frame = CGRectMake(0, 0, thickness, CGRectGetHeight(self.frame))
break
case UIRectEdge.Right:
border.frame = CGRectMake(CGRectGetWidth(self.frame) - thickness, 0, thickness, CGRectGetHeight(self.frame))
break
default:
break
}
border.backgroundColor = color.CGColor;
self.addSublayer(border)
}
}
Je suis venu avec une solution en utilisant Swift 4.1
qui utilise AutoLayout
et UIViews
afin qu'il redimensionne avec la vue.
Il est basé sur la réponse de @AdamWaite mais résout le problème des cellules de la vue tableau dans lesquelles les cellules sont réutilisées. Si la bordure précédente n'est pas supprimée avant d'en ajouter une nouvelle, la cellule réutilisée contiendra plusieurs bordures.
Ce problème est résolu en créant une classe factice BorderView, en recherchant les bordures de la sous-vue et en les supprimant.
Ce code utilise SnapKit
pour les contraintes et CocoaLumberjack
pour le débogage. Si vous ne les utilisez pas, la conversion devrait être assez simple
class BorderView: UIView {
}
extension UIView {
private func addSidedBorder(toEdge Edge: UIRectEdge, withColor color: UIColor, inset: CGFloat, thickness: CGFloat) {
let border = BorderView(frame: .zero)
border.backgroundColor = color
addSubview(border)
border.snp.makeConstraints { make in
switch Edge {
case .top:
make.top.equalToSuperview()
make.height.equalTo(thickness)
make.left.right.equalToSuperview().inset(inset)
case .left:
make.left.equalToSuperview()
make.width.equalTo(thickness)
make.top.bottom.equalToSuperview().inset(inset)
case .bottom:
make.bottom.equalToSuperview()
make.height.equalTo(thickness)
make.left.right.equalToSuperview().inset(inset)
case .right:
make.right.equalToSuperview()
make.width.equalTo(thickness)
make.top.bottom.equalToSuperview().inset(inset)
default:
DDLogWarn("Invalid sided border given in ExtendedUIView, border not added correctly")
}
}
}
func addBorder(toEdge Edge: UIRectEdge, withColor color: UIColor = .black, inset: CGFloat = 0.0, thickness: CGFloat = 1.0) {
// Remove existing borders from view and readd them
for view in subviews {
if view is BorderView {
view.removeFromSuperview()
}
}
if Edge.contains(.all) {
addSidedBorder(toEdge: .top, withColor: color, inset: inset, thickness: thickness)
addSidedBorder(toEdge: .left, withColor: color, inset: inset, thickness: thickness)
addSidedBorder(toEdge: .bottom, withColor: color, inset: inset, thickness: thickness)
addSidedBorder(toEdge: .right, withColor: color, inset: inset, thickness: thickness)
} else {
if Edge.contains(.top) {
addSidedBorder(toEdge: .top, withColor: color, inset: inset, thickness: thickness)
}
if Edge.contains(.left) {
addSidedBorder(toEdge: .left, withColor: color, inset: inset, thickness: thickness)
}
if Edge.contains(.bottom) {
addSidedBorder(toEdge: .bottom, withColor: color, inset: inset, thickness: thickness)
}
if Edge.contains(.right) {
addSidedBorder(toEdge: .right, withColor: color, inset: inset, thickness: thickness)
}
}
}
}
Ajoutez ce code, puis dans une classe qui sous-classe UIView
, appelez:
view.addBorder(toEdge: [.left, .right], withColor: .red, inset: 0.0, thickness: 1.0)
Si je construis à partir du storyboard, je préfère ajouter une UIView
derrière ma utile UIView
... Si je veux créer une bordure au-dessus de ma UIView
, j'augmente simplement la hauteur de l'arrière-plan UIView
de ma largeur. La même chose peut être faite pour tout autre côté :)
Swift 3 version
extension UIView {
enum ViewSide {
case Top, Bottom, Left, Right
}
func addBorder(toSide side: ViewSide, withColor color: UIColor, andThickness thickness: CGFloat) {
let border = CALayer()
border.backgroundColor = color.cgColor
switch side {
case .Top:
border.frame = CGRect(x: 0, y: 0, width: frame.size.width, height: thickness)
case .Bottom:
border.frame = CGRect(x: 0, y: frame.size.height - thickness, width: frame.size.width, height: thickness)
case .Left:
border.frame = CGRect(x: 0, y: 0, width: thickness, height: frame.size.height)
case .Right:
border.frame = CGRect(x: frame.size.width - thickness, y: 0, width: thickness, height: frame.size.height)
}
layer.addSublayer(border)
}
}
Afin de définir la bordure correspondante, vous devez remplacer viewDidLayoutSubviews () method:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
yourView.addBorder(toSide: UIView.ViewSide.Top, withColor: UIColor.lightGray, andThickness: 1)
Voici une version Swift 4 de Réponse de Pauls
func addTopBorder(color: UIColor, thickness: CGFloat) {
let border = UIView()
border.backgroundColor = color
border.autoresizingMask = [.flexibleWidth, .flexibleBottomMargin]
border.frame = CGRect(x: 0, y: 0, width: frame.size.width, height: thickness)
addSubview(border)
}
func addBottomBorder(color: UIColor, thickness: CGFloat) {
let border = UIView()
border.backgroundColor = color
border.autoresizingMask = [.flexibleWidth, .flexibleTopMargin]
border.frame = CGRect(x: 0, y: frame.size.height - thickness, width: frame.size.width, height: thickness)
addSubview(border)
}
func addLeftBorder(color: UIColor, thickness: CGFloat) {
let border = UIView()
border.backgroundColor = color
border.autoresizingMask = [.flexibleHeight, .flexibleRightMargin]
border.frame = CGRect(x: 0, y: 0, width: thickness, height: frame.size.height)
addSubview(border)
}
func addRightBorder(color: UIColor, thickness: CGFloat) {
let border = UIView()
border.backgroundColor = color
border.autoresizingMask = [.flexibleHeight, .flexibleLeftMargin]
border.frame = CGRect(x: frame.size.width - thickness, y: 0, width: thickness, height: frame.size.height)
addSubview(border)
}
extension UIView {
func addBorder(Edge: UIRectEdge, color: UIColor, borderWidth: CGFloat) {
let seperator = UIView()
self.addSubview(seperator)
seperator.translatesAutoresizingMaskIntoConstraints = false
seperator.backgroundColor = color
if Edge == .top || Edge == .bottom
{
seperator.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 0).isActive = true
seperator.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: 0).isActive = true
seperator.heightAnchor.constraint(equalToConstant: borderWidth).isActive = true
if Edge == .top
{
seperator.topAnchor.constraint(equalTo: self.topAnchor, constant: 0).isActive = true
}
else
{
seperator.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 0).isActive = true
}
}
else if Edge == .left || Edge == .right
{
seperator.topAnchor.constraint(equalTo: self.topAnchor, constant: 0).isActive = true
seperator.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 0).isActive = true
seperator.widthAnchor.constraint(equalToConstant: borderWidth).isActive = true
if Edge == .left
{
seperator.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 0).isActive = true
}
else
{
seperator.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: 0).isActive = true
}
}
}
}
Inspiré par @Addison, j'ai réécrit l'extension sans utiliser de framework tiers, car il utilisait SnapKit et CocoaLumberjack.
Comme dans l’approche @Addisons, je supprime également les frontières précédemment ajoutées. Cette implémentation doit donc jouer à Nice avec des vues réutilisables sous forme de cellules de tableau et de cellules de collecte.
fileprivate class BorderView: UIView {} // dummy class to help us differentiate among border views and other views
// to enabling us to remove existing borders and place new ones
extension UIView {
func setBorders(toEdges edges: [UIRectEdge], withColor color: UIColor, inset: CGFloat = 0, thickness: CGFloat) {
// Remove existing edges
for view in subviews {
if view is BorderView {
view.removeFromSuperview()
}
}
// Add new edges
if edges.contains(.all) {
addSidedBorder(toEdge: [.left,.right, .top, .bottom], withColor: color, inset: inset, thickness: thickness)
}
if edges.contains(.left) {
addSidedBorder(toEdge: [.left], withColor: color, inset: inset, thickness: thickness)
}
if edges.contains(.right) {
addSidedBorder(toEdge: [.right], withColor: color, inset: inset, thickness: thickness)
}
if edges.contains(.top) {
addSidedBorder(toEdge: [.top], withColor: color, inset: inset, thickness: thickness)
}
if edges.contains(.bottom) {
addSidedBorder(toEdge: [.bottom], withColor: color, inset: inset, thickness: thickness)
}
}
private func addSidedBorder(toEdge edges: [RectangularEdges], withColor color: UIColor, inset: CGFloat = 0, thickness: CGFloat) {
for Edge in edges {
let border = BorderView(frame: .zero)
border.backgroundColor = color
addSubview(border)
border.translatesAutoresizingMaskIntoConstraints = false
switch Edge {
case .left:
NSLayoutConstraint.activate([
border.leftAnchor.constraint(equalTo: self.leftAnchor, constant: inset),
border.topAnchor.constraint(equalTo: self.topAnchor, constant: inset),
border.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -inset),
NSLayoutConstraint(item: border, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .width, multiplier: 1, constant: thickness) ])
case .right:
NSLayoutConstraint.activate([
border.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -inset),
border.topAnchor.constraint(equalTo: self.topAnchor, constant: inset),
border.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -inset),
NSLayoutConstraint(item: border, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .width, multiplier: 1, constant: thickness) ])
case .top:
NSLayoutConstraint.activate([
border.leftAnchor.constraint(equalTo: self.leftAnchor, constant: inset),
border.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -inset),
border.topAnchor.constraint(equalTo: self.topAnchor, constant: inset),
NSLayoutConstraint(item: border, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: thickness) ])
case .bottom:
NSLayoutConstraint.activate([
border.leftAnchor.constraint(equalTo: self.leftAnchor, constant: inset),
border.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -inset),
border.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -inset),
NSLayoutConstraint(item: border, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: thickness) ])
}
}
}
private enum RectangularEdges {
case left
case right
case top
case bottom
}
}
Si quelqu'un a besoin de la version Xamarin:
public static class UIUtils
{
public static void AddBorder(this CALayer cALayer, UIRectEdge Edge, UIColor color, float thickness)
{
var border = new CALayer();
switch (Edge)
{
case UIRectEdge.Top:
border.Frame = new CGRect(0, 0, cALayer.Frame.Width, height: thickness);
break;
case UIRectEdge.Bottom:
border.Frame = new CGRect(0, cALayer.Frame.Height - thickness, width: cALayer.Frame.Width, height: thickness);
break;
case UIRectEdge.Left:
border.Frame = new CGRect(0, 0, width: thickness, height: cALayer.Frame.Height);
break;
case UIRectEdge.Right:
border.Frame = new CGRect(cALayer.Frame.Width - thickness, y: 0, width: thickness, height: cALayer.Frame.Height);
break;
default: break;
}
border.BackgroundColor = color.CGColor;
cALayer.AddSublayer(border);
}
}
Vous pouvez également consulter cette collection de catégories UIKit et Foundation: https://github.com/leszek-s/LSCategories
Il permet d'ajouter des bordures d'un côté d'UIView avec une seule ligne de code:
[self.someView lsAddBorderOnEdge:UIRectEdgeTop color:[UIColor blueColor] width:2];
et il gère correctement la rotation de vue alors que la plupart des réponses postées ici ne le traitent pas bien.
Convertir DanShev répondre à Swift 3
extension CALayer {
func addBorder(Edge: UIRectEdge, color: UIColor, thickness: CGFloat) {
let border = CALayer()
switch Edge {
case .top:
border.frame = CGRect(x: 0, y: 0, width: self.frame.width, height: thickness)
break
case .bottom:
border.frame = CGRect(x: 0, y: self.frame.height - thickness, width: self.frame.width, height: thickness)
break
case .left:
border.frame = CGRect(x: 0, y: 0, width: thickness, height: self.frame.height)
break
case .right:
border.frame = CGRect(x: self.frame.width - thickness, y: 0, width: thickness, height: self.frame.height)
break
default:
break
}
border.backgroundColor = color.cgColor;
self.addSublayer(border)
}
}
Personnellement, j'aime bien la sous-classification de la vue + drawRect, mais voici juste une autre façon de procéder (et cela marche un peu dans le même sens que la réponse acceptée par @If Pollavith):
Votre nouvelle couche de bordure peut être configurée pour avoir les dimensions de votre choix. Ainsi, à l'instar de @If Pollavith, vous créez un calque aussi haut que vous le souhaitez et aussi large que la vue que vous souhaitez voir encadrée. Utilisez la définition du cadre du calque pour le placer où vous le souhaitez, puis ajoutez-le en tant que sous-calque à votre vue.
Pour référence, ma propre exigence était de placer une bordure du côté gauche de la vue (veuillez ne pas copier-coller ce code et ne pas me «cacher» simplement parce qu'il ne met pas de bordure en haut de la vue - modifier le code ci-dessous est assez simple):
CALayer *leftBorder = [CALayer layer];
leftBorder.borderColor = [UIColor colorWithRed:0.0 green:91.0/255.0 blue:141.0/255.0 alpha:1.0].CGColor;
leftBorder.borderWidth = 1;
leftBorder.frame = CGRectMake(0, 0, 1.0, CGRectGetHeight(self.myTargetView.frame));
[self.myTargetView.layer addSublayer:leftBorder];
J'imagine que le seul avantage modéré que nous obtenons à faire cela et à créer un petit UIView ou UILabel est que CALayer est censé être «plus léger», et il existe de nombreux points de vue intéressants (en tant qu'opinions) à propos de drawRect par rapport à l'utilisation de CALayers : iOS: Utilisation du 'drawRect:' d'UIView par rapport au delagate 'de sa couche' drawLayer: inContext: ' ).
J'aime la couleur bleue.
Dans Swift 4 et 3
let borderThickness = 2
let topBorder = UIView()
topBorder.backgroundColor = UIColor.red
topBorder.frame = CGRect(x: 0, y: 0, width:
Int(yourViewFromOutlet.frame.size.width), height:
borderThickness)
yourViewFromOutlet.addSubview(topBorder)
Pour Xamarin en C #, je crée simplement la bordure en ligne lors de l’ajout du sous-calque
View.Layer.AddSublayer(new CALayer()
{
BackgroundColor = UIColor.Black.CGColor,
Frame = new CGRect(0, 0, View.Frame.Width, 0.5f)
});
Vous pouvez organiser cela (comme suggéré par d'autres) pour les bordures inférieure, gauche et droite.
Pour moi ça marche
extension UIView {
func addBorders(edges: UIRectEdge = .all, color: UIColor = .black, width: CGFloat = 1.0) {
func createBorder() -> UIView {
let borderView = UIView(frame: CGRect.zero)
borderView.translatesAutoresizingMaskIntoConstraints = false
borderView.backgroundColor = color
return borderView
}
if (edges.contains(.all) || edges.contains(.top)) {
let topBorder = createBorder()
self.addSubview(topBorder)
NSLayoutConstraint.activate([
topBorder.topAnchor.constraint(equalTo: self.topAnchor),
topBorder.leadingAnchor.constraint(equalTo: self.leadingAnchor),
topBorder.trailingAnchor.constraint(equalTo: self.trailingAnchor),
topBorder.heightAnchor.constraint(equalToConstant: width)
])
}
if (edges.contains(.all) || edges.contains(.left)) {
let leftBorder = createBorder()
self.addSubview(leftBorder)
NSLayoutConstraint.activate([
leftBorder.topAnchor.constraint(equalTo: self.topAnchor),
leftBorder.bottomAnchor.constraint(equalTo: self.bottomAnchor),
leftBorder.leadingAnchor.constraint(equalTo: self.leadingAnchor),
leftBorder.widthAnchor.constraint(equalToConstant: width)
])
}
if (edges.contains(.all) || edges.contains(.right)) {
let rightBorder = createBorder()
self.addSubview(rightBorder)
NSLayoutConstraint.activate([
rightBorder.topAnchor.constraint(equalTo: self.topAnchor),
rightBorder.bottomAnchor.constraint(equalTo: self.bottomAnchor),
rightBorder.trailingAnchor.constraint(equalTo: self.trailingAnchor),
rightBorder.widthAnchor.constraint(equalToConstant: width)
])
}
if (edges.contains(.all) || edges.contains(.bottom)) {
let bottomBorder = createBorder()
self.addSubview(bottomBorder)
NSLayoutConstraint.activate([
bottomBorder.bottomAnchor.constraint(equalTo: self.bottomAnchor),
bottomBorder.leadingAnchor.constraint(equalTo: self.leadingAnchor),
bottomBorder.trailingAnchor.constraint(equalTo: self.trailingAnchor),
bottomBorder.heightAnchor.constraint(equalToConstant: width)
])
}
}
}
Remarque: la plupart des solutions présentées ici ne sont pas adaptatives et ne seront pas redimensionnées. Les solutions qui redimensionneront auront un impact massif sur votre temps de démarrage car elles utilisent beaucoup de temps processeur.
Vous pouvez utiliser cette solution ci-dessous. Cela fonctionne sur UIBezierPaths, qui sont plus légers que les couches, ce qui permet des temps de démarrage rapides. Il est facile à utiliser, voir les instructions ci-dessous.
class ResizeBorderView: UIView {
var color = UIColor.white
var lineWidth: CGFloat = 1
var edges = [UIRectEdge](){
didSet {
setNeedsDisplay()
}
}
override func draw(_ rect: CGRect) {
if edges.contains(.top) || edges.contains(.all){
let path = UIBezierPath()
path.lineWidth = lineWidth
color.setStroke()
UIColor.blue.setFill()
path.move(to: CGPoint(x: 0, y: 0 + lineWidth / 2))
path.addLine(to: CGPoint(x: self.bounds.width, y: 0 + lineWidth / 2))
path.stroke()
}
if edges.contains(.bottom) || edges.contains(.all){
let path = UIBezierPath()
path.lineWidth = lineWidth
color.setStroke()
UIColor.blue.setFill()
path.move(to: CGPoint(x: 0, y: self.bounds.height - lineWidth / 2))
path.addLine(to: CGPoint(x: self.bounds.width, y: self.bounds.height - lineWidth / 2))
path.stroke()
}
if edges.contains(.left) || edges.contains(.all){
let path = UIBezierPath()
path.lineWidth = lineWidth
color.setStroke()
UIColor.blue.setFill()
path.move(to: CGPoint(x: 0 + lineWidth / 2, y: 0))
path.addLine(to: CGPoint(x: 0 + lineWidth / 2, y: self.bounds.height))
path.stroke()
}
if edges.contains(.right) || edges.contains(.all){
let path = UIBezierPath()
path.lineWidth = lineWidth
color.setStroke()
UIColor.blue.setFill()
path.move(to: CGPoint(x: self.bounds.width - lineWidth / 2, y: 0))
path.addLine(to: CGPoint(x: self.bounds.width - lineWidth / 2, y: self.bounds.height))
path.stroke()
}
}
}
Pour régler les bordures supérieure et inférieure pour une vue UIV dans Swift.
let topBorder = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 1))
topBorder.backgroundColor = UIColor.black
myView.addSubview(topBorder)
let bottomBorder = UIView(frame: CGRect(x: 0, y: myView.frame.size.height - 1, width: 10, height: 1))
bottomBorder.backgroundColor = UIColor.black
myView.addSubview(bottomBorder)
En plus de n8tr peut ajouter qu’il existe une possibilité de les définir à partir du storyboard:
- ajoute deux propriétés comme borderColor
et borderWidth
dans le fichier .h;
- alors vous pourriez ajouter keyPaths
dans le storyboard, voir le lien vers capture d'écran