Ma question porte sur le titre.
Je ne sais pas comment ajouter une bordure dans un côté spécifique, en haut ou en bas, de n'importe quel côté ...
layer.border
dessine la bordure pour toute la vue ...
Ma question porte sur le titre.
Je ne sais pas comment ajouter une bordure dans un côté spécifique, en haut ou en bas, de n'importe quel côté ...
layer.border
dessine la bordure pour toute la vue ...
Réponses:
Je considère ici un sous UIView
-classement et une drawRect
surpuissance. Pourquoi ne pas ajouter une extension 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 tout autre. Passez d'autres arguments à vos méthodes pour définir d'autres couleurs et largeurs. De nombreuses options.
Ajout de la capacité des coins arrondis au message original d'Adam Waite et des multiples modifications
Important!: N'oubliez pas d'ajouter « label.layoutIfNeeded()
» juste avant d'appeler «addborder» comme indiqué précédemment
Remarque: je n'ai testé cela que sur UILabels
.
extension CALayer {
enum BorderSide {
case top
case right
case bottom
case left
case notRight
case notLeft
case topAndBottom
case all
}
enum Corner {
case topLeft
case topRight
case bottomLeft
case bottomRight
}
func addBorder(side: BorderSide, thickness: CGFloat, color: CGColor, maskedCorners: CACornerMask? = nil) {
var topWidth = frame.size.width; var bottomWidth = topWidth
var leftHeight = frame.size.height; var rightHeight = leftHeight
var topXOffset: CGFloat = 0; var bottomXOffset: CGFloat = 0
var leftYOffset: CGFloat = 0; var rightYOffset: CGFloat = 0
// Draw the corners and set side offsets
switch maskedCorners {
case [.layerMinXMinYCorner, .layerMaxXMinYCorner]: // Top only
addCorner(.topLeft, thickness: thickness, color: color)
addCorner(.topRight, thickness: thickness, color: color)
topWidth -= cornerRadius*2
leftHeight -= cornerRadius; rightHeight -= cornerRadius
topXOffset = cornerRadius; leftYOffset = cornerRadius; rightYOffset = cornerRadius
case [.layerMinXMaxYCorner, .layerMaxXMaxYCorner]: // Bottom only
addCorner(.bottomLeft, thickness: thickness, color: color)
addCorner(.bottomRight, thickness: thickness, color: color)
bottomWidth -= cornerRadius*2
leftHeight -= cornerRadius; rightHeight -= cornerRadius
bottomXOffset = cornerRadius
case [.layerMinXMinYCorner, .layerMinXMaxYCorner]: // Left only
addCorner(.topLeft, thickness: thickness, color: color)
addCorner(.bottomLeft, thickness: thickness, color: color)
topWidth -= cornerRadius; bottomWidth -= cornerRadius
leftHeight -= cornerRadius*2
leftYOffset = cornerRadius; topXOffset = cornerRadius; bottomXOffset = cornerRadius;
case [.layerMaxXMinYCorner, .layerMaxXMaxYCorner]: // Right only
addCorner(.topRight, thickness: thickness, color: color)
addCorner(.bottomRight, thickness: thickness, color: color)
topWidth -= cornerRadius; bottomWidth -= cornerRadius
rightHeight -= cornerRadius*2
rightYOffset = cornerRadius
case [.layerMaxXMinYCorner, .layerMaxXMaxYCorner, // All
.layerMinXMaxYCorner, .layerMinXMinYCorner]:
addCorner(.topLeft, thickness: thickness, color: color)
addCorner(.topRight, thickness: thickness, color: color)
addCorner(.bottomLeft, thickness: thickness, color: color)
addCorner(.bottomRight, thickness: thickness, color: color)
topWidth -= cornerRadius*2; bottomWidth -= cornerRadius*2
topXOffset = cornerRadius; bottomXOffset = cornerRadius
leftHeight -= cornerRadius*2; rightHeight -= cornerRadius*2
leftYOffset = cornerRadius; rightYOffset = cornerRadius
default: break
}
// Draw the sides
switch side {
case .top:
addLine(x: topXOffset, y: 0, width: topWidth, height: thickness, color: color)
case .right:
addLine(x: frame.size.width - thickness, y: rightYOffset, width: thickness, height: rightHeight, color: color)
case .bottom:
addLine(x: bottomXOffset, y: frame.size.height - thickness, width: bottomWidth, height: thickness, color: color)
case .left:
addLine(x: 0, y: leftYOffset, width: thickness, height: leftHeight, color: color)
// Multiple Sides
case .notRight:
addLine(x: topXOffset, y: 0, width: topWidth, height: thickness, color: color)
addLine(x: 0, y: leftYOffset, width: thickness, height: leftHeight, color: color)
addLine(x: bottomXOffset, y: frame.size.height - thickness, width: bottomWidth, height: thickness, color: color)
case .notLeft:
addLine(x: topXOffset, y: 0, width: topWidth, height: thickness, color: color)
addLine(x: frame.size.width - thickness, y: rightYOffset, width: thickness, height: rightHeight, color: color)
addLine(x: bottomXOffset, y: frame.size.height - thickness, width: bottomWidth, height: thickness, color: color)
case .topAndBottom:
addLine(x: topXOffset, y: 0, width: topWidth, height: thickness, color: color)
addLine(x: bottomXOffset, y: frame.size.height - thickness, width: bottomWidth, height: thickness, color: color)
case .all:
addLine(x: topXOffset, y: 0, width: topWidth, height: thickness, color: color)
addLine(x: frame.size.width - thickness, y: rightYOffset, width: thickness, height: rightHeight, color: color)
addLine(x: bottomXOffset, y: frame.size.height - thickness, width: bottomWidth, height: thickness, color: color)
addLine(x: 0, y: leftYOffset, width: thickness, height: leftHeight, color: color)
}
}
private func addLine(x: CGFloat, y: CGFloat, width: CGFloat, height: CGFloat, color: CGColor) {
let border = CALayer()
border.frame = CGRect(x: x, y: y, width: width, height: height)
border.backgroundColor = color
addSublayer(border)
}
private func addCorner(_ corner: Corner, thickness: CGFloat, color: CGColor) {
// Set default to top left
let width = frame.size.width; let height = frame.size.height
var x = cornerRadius
var startAngle: CGFloat = .pi; var endAngle: CGFloat = .pi*3/2
switch corner {
case .bottomLeft: startAngle = .pi/2; endAngle = .pi
case .bottomRight:
x = width - cornerRadius
startAngle = 0; endAngle = .pi/2
case .topRight:
x = width - cornerRadius
startAngle = .pi*3/2; endAngle = 0
default: break
}
let cornerPath = UIBezierPath(arcCenter: CGPoint(x: x, y: height / 2),
radius: cornerRadius - thickness,
startAngle: startAngle,
endAngle: endAngle,
clockwise: true)
let cornerShape = CAShapeLayer()
cornerShape.path = cornerPath.cgPath
cornerShape.lineWidth = thickness
cornerShape.strokeColor = color
cornerShape.fillColor = nil
addSublayer(cornerShape)
}
}
view.layoutIfNeeded()
juste avant d'appeler view.layer.addBorder(...)
. Ensuite, cela fonctionne dans Swift 3
override func viewDidLayoutSubviews()
Le meilleur moyen pour moi est une catégorie sur UIView, mais adding views
au lieu de CALayers, nous pouvons donc nous take advantage of AutoresizingMasks
assurer que les bordures sont redimensionnées avec le superview.
Objectif c
- (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 5
func addTopBorder(with color: UIColor?, andWidth borderWidth: CGFloat) {
let border = UIView()
border.backgroundColor = color
border.autoresizingMask = [.flexibleWidth, .flexibleBottomMargin]
border.frame = CGRect(x: 0, y: 0, width: frame.size.width, height: borderWidth)
addSubview(border)
}
func addBottomBorder(with color: UIColor?, andWidth borderWidth: CGFloat) {
let border = UIView()
border.backgroundColor = color
border.autoresizingMask = [.flexibleWidth, .flexibleTopMargin]
border.frame = CGRect(x: 0, y: frame.size.height - borderWidth, width: frame.size.width, height: borderWidth)
addSubview(border)
}
func addLeftBorder(with color: UIColor?, andWidth borderWidth: CGFloat) {
let border = UIView()
border.backgroundColor = color
border.frame = CGRect(x: 0, y: 0, width: borderWidth, height: frame.size.height)
border.autoresizingMask = [.flexibleHeight, .flexibleRightMargin]
addSubview(border)
}
func addRightBorder(with color: UIColor?, andWidth borderWidth: CGFloat) {
let border = UIView()
border.backgroundColor = color
border.autoresizingMask = [.flexibleHeight, .flexibleLeftMargin]
border.frame = CGRect(x: frame.size.width - borderWidth, y: 0, width: borderWidth, height: frame.size.height)
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: frame.width, height: thickness)
case UIRectEdge.bottom:
border.frame = CGRect(x:0, y: frame.height - thickness, width: frame.width, height:thickness)
case UIRectEdge.left:
border.frame = CGRect(x:0, y:0, width: thickness, height: frame.height)
case UIRectEdge.right:
border.frame = CGRect(x: frame.width - thickness, y: 0, width: thickness, height: frame.height)
default: do {}
}
border.backgroundColor = color.cgColor
addSublayer(border)
}
}
Sous UIView
- classe et implémentation 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 trace une ligne rouge de 2 pixels comme bordure supérieure. Toutes les autres variantes que vous mentionnez sont laissées comme un exercice trivial pour le lecteur.
Le guide de programmation Quartz 2D est recommandé.
UIView
sous-classe peut avoir une propriété qui détermine les bordures drawRect:
dessinées. Cette propriété peut être définie avec NS_OPTIONS
afin qu'elle définisse un masque de bits comme le UIViewAutoresizing
masque de bits. Si - pour une raison quelconque - vous vous UIView
opposez vraiment fortement au sous- classement, ajoutez simplement une petite sous-vue de 1 à 2 pixels de haut (ou de large) et donnez-lui les dimensions que vous souhaitez simuler une bordure.
Code pour la réponse sélectionnée, au cas où quelqu'un le voudrait.
REMARQUE: cela ne fonctionne pas avec la mise en page automatique (alias, rotation de l'appareil en paysage, etc.).
Définissez d'abord une épaisseur:
NSInteger borderThickness = 1;
Ensuite, copiez simplement, utilisez 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];
Bordure gauche
UIView *leftBorder = [UIView new];
leftBorder.backgroundColor = [UIColor lightGrayColor];
leftBorder.frame = CGRectMake(0, 0, borderThickness, myView.frame.size.height);
[myView addSubview:leftBorder];
Bordure 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];
Ancienne question, mais la solution de mise en page automatique avec les ajustements de bordure d'exécution est toujours absente.
borders(for: [.left, .bottom], width: 2, color: .red)
L'extension UIView suivante ajoutera la bordure uniquement sur les bords donnés. Si vous modifiez les bords lors de l'exécution, les bordures s'ajusteront 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]))
}
}
}
}
}
Version Swift:
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, vérifiez mon dépôt ici: https://github.com/goktugyil/EZSwiftExtensions/blob/master/Sources/UIViewExtensions.swift
Regardez les parties addBorder
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 qui fonctionne avec AutoLayout - utilisez View au lieu de Layer pour vous assurer que nous pouvons 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
}
}
}
J'ai pris les réponses d'Adam Waite et de Paul et les ai combinées. J'ai également ajouté la possibilité de canaliser les arêtes sélectionnées ensemble, vous n'avez donc besoin d'appeler qu'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];
}
}
// MARQUE: - Ajouter la bordure gauche pour la vue
(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];
}
// MARQUE: - Ajouter une bordure droite pour la vue
(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 apporté quelques modifications à la réponse de Dan afin que je puisse ajouter des bordures à plusieurs bords 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)
}
}
}
En m'appuyant 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 fonctionne avec des contraintes: lien github
En utilisant CGContextFillRect au lieu de CGContextStrokePath, j'ai pu de manière prévisible garder les lignes complètement solides et à l'intérieur les limites de la vue.
Voici mon article de blog à ce sujet: http://natrosoft.com/?p=55
- En gros, déposez simplement un UIView dans Interface Builder et changez son type de classe en NAUIViewWithBorders.
- Ensuite, dans viewDidLoad de votre VC, faites quelque chose comme:
/* 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 l'implémentation. Il existe également un projet de démonstration. J'espère que cela aide quelqu'un :)
Ma réponse à une question similaire: https://stackoverflow.com/a/27141956/435766 Personnellement, je préfère descendre la route des catégories sur celle-là, car je veux pouvoir l'utiliser sur n'importe quelle sous-classe d'UIView.
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
}
}
}
}
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 pour qu'elle soit votre couleur de bordure. Définissez l'origine (x,y)
de votre étiquette comme étant l'origine (x,y)
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 votre bordure en haut de votre UIView
). Et cela devrait faire l'affaire.
Version Swift 3
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 la méthode viewDidLayoutSubviews () :
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
yourView.addBorder(toSide: UIView.ViewSide.Top, withColor: UIColor.lightGray, andThickness: 1)
Publiez simplement ici pour aider quelqu'un qui cherche à ajouter des bordures J'ai apporté quelques modifications à la réponse acceptée ici, étiquette rapide seulement bordure gauche . Largeur modifiée en cas UIRectEdge.Top
de CGRectGetHeight(self.frame)
à CGRectGetWidth(self.frame)
et en 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)
}
}
Au cas où quelqu'un aurait 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);
}
}
Voici une version Swift 4 de la 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)
}
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 bordures précédemment ajoutées, cette implémentation devrait donc bien fonctionner avec des vues réutilisables en tant que cellules de tableau et cellules de collection.
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 je construis à partir du storyboard, je préfère ajouter un UIView
derrière mon utile UIView
... Si je veux créer une bordure sur le dessus de mon UIView
, j'augmente simplement la hauteur de l'arrière-plan UIView
de ma largeur de bordure .. La même chose peut être fait pour tout autre côté :)
Personnellement, j'aime le sous-classement de la vue + drawRect, mais voici juste une autre façon de procéder (et cela fonctionne en quelque sorte dans le même sens que la réponse acceptée par @If Pollavith):
Votre nouveau calque de bordure peut être configuré pour avoir les dimensions que vous souhaitez. Ainsi, comme @Si la réponse de Pollavith, vous créez un calque aussi haut que vous le souhaitez et aussi large que la vue que vous souhaitez encadrer. Utilisez la définition de 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 mettre une bordure sur le côté GAUCHE de la vue (veuillez ne pas couper et coller ce code et dis-moi juste 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];
Je suppose que le seul avantage modéré par rapport à cela et à créer un petit UIView ou UILabel est que le CALayer est censé être `` plus léger '', et il y a beaucoup de points de vue intéressants (comme dans les opinions) sur la sur-équitation de drawRect par rapport à l'utilisation de CALayers (comme ici : iOS: Utilisation de 'drawRect:' d'UIView par rapport à la délagation de sa couche 'drawLayer: inContext:' ).
J'aime la couleur bleue.
Convertir la réponse DanShev en 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)
}
}
Pour Xamarin en C #, je crée simplement la bordure en ligne lors de l'ajout de la sous-couche
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 en bas, à gauche et à droite.
Vous pouvez également consulter cette collection de catégories UIKit et Foundation: https://github.com/leszek-s/LSCategories
Il permet d'ajouter une bordure sur un côté de UIView avec une seule ligne de code:
[self.someView lsAddBorderOnEdge:UIRectEdgeTop color:[UIColor blueColor] width:2];
et il gère correctement la rotation des vues alors que la plupart des réponses publiées ici ne le gèrent pas bien.
Remarque: la plupart des solutions ici ne sont pas adaptatives et ne seront pas redimensionnées. Les solutions qui seront redimensionnées auront un impact énorme sur votre temps de démarrage car elles utilisent beaucoup de CPU.
Vous pouvez utiliser cette solution ci-dessous. Il fonctionne sur UIBezierPaths qui sont plus légers que les couches, ce qui entraîne 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 définir la bordure supérieure et la bordure inférieure d'un UIView 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)