ios uiview border

ios - UIView borde inferior?



border (14)

Aquí hay una extensión Swift más general para crear bordes para cualquier subclase UIView :

import UIKit extension UIView { func addTopBorderWithColor(color: UIColor, width: CGFloat) { let border = CALayer() border.backgroundColor = color.CGColor border.frame = CGRectMake(0, 0, self.frame.size.width, width) self.layer.addSublayer(border) } func addRightBorderWithColor(color: UIColor, width: CGFloat) { let border = CALayer() border.backgroundColor = color.CGColor border.frame = CGRectMake(self.frame.size.width - width, 0, width, self.frame.size.height) self.layer.addSublayer(border) } func addBottomBorderWithColor(color: UIColor, width: CGFloat) { let border = CALayer() border.backgroundColor = color.CGColor border.frame = CGRectMake(0, self.frame.size.height - width, self.frame.size.width, width) self.layer.addSublayer(border) } func addLeftBorderWithColor(color: UIColor, width: CGFloat) { let border = CALayer() border.backgroundColor = color.CGColor border.frame = CGRectMake(0, 0, width, self.frame.size.height) self.layer.addSublayer(border) } }

Swift 3

extension UIView { func addTopBorderWithColor(color: UIColor, width: CGFloat) { let border = CALayer() border.backgroundColor = color.cgColor border.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: width) self.layer.addSublayer(border) } func addRightBorderWithColor(color: UIColor, width: CGFloat) { let border = CALayer() border.backgroundColor = color.cgColor border.frame = CGRect(x: self.frame.size.width - width, y: 0, width: width, height: self.frame.size.height) self.layer.addSublayer(border) } func addBottomBorderWithColor(color: UIColor, width: CGFloat) { let border = CALayer() border.backgroundColor = color.cgColor border.frame = CGRect(x: 0, y: self.frame.size.height - width, width: self.frame.size.width, height: width) self.layer.addSublayer(border) } func addLeftBorderWithColor(color: UIColor, width: CGFloat) { let border = CALayer() border.backgroundColor = color.cgColor border.frame = CGRect(x: 0, y: 0, width: width, height: self.frame.size.height) self.layer.addSublayer(border) } }

Para un UIScrollView *toScrollView (que es el ancho de la pantalla), quiero agregar un borde inferior gris (exactamente como el del campo de la vista de redacción de la aplicación de mensajes nativa del iPhone).

Para lograr esto, seguí Cocoa Touch: ¿Cómo cambiar el color y el grosor del borde de UIView? y simplemente cubrió el borde superior con la UINavigationBar personalizada e hizo la toScrollView x de toScrollView -1 y el ancho 322 para que los bordes izquierdo y derecho quedaran fuera de la pantalla.

Esto se ve bien, pero es una especie de truco, y me preguntaba si hay una mejor manera de hacerlo.

- (void)viewDidLoad { [super viewDidLoad]; // Add UINavigationBar *navigationBar at top. self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelAction)]; UINavigationBar *navigationBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 44.0f)]; navigationBar.items = [NSArray arrayWithObject:self.navigationItem]; // Add UIScrollView *toScrollView below navigationBar. UIScrollView *toScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(-1.0f, 43.0f, 322.0f, 45.0f)]; toScrollView.backgroundColor = [UIColor whiteColor]; toScrollView.layer.borderColor = [UIColor colorWithWhite:0.8f alpha:1.0f].CGColor; toScrollView.layer.borderWidth = 1.0f; [self.view addSubview:toScrollView]; [self.view addSubview:navigationBar]; // covers top of toScrollView }


El problema con estos métodos de extensión es que cuando UIView / UIButton posteriormente ajusta su tamaño, no tiene posibilidad de cambiar el tamaño del CALayer para que coincida con el nuevo tamaño. Lo cual te dejará con un borde fuera de lugar. Descubrí que era mejor subclasificar mi UIButton; por supuesto, también podías subclase otras UIViews. Aquí hay un código:

enum BorderedButtonSide { case Top, Right, Bottom, Left } class BorderedButton : UIButton { private var borderTop: CALayer? private var borderTopWidth: CGFloat? private var borderRight: CALayer? private var borderRightWidth: CGFloat? private var borderBottom: CALayer? private var borderBottomWidth: CGFloat? private var borderLeft: CALayer? private var borderLeftWidth: CGFloat? func setBorder(side: BorderedButtonSide, _ color: UIColor, _ width: CGFloat) { let border = CALayer() border.backgroundColor = color.CGColor switch side { case .Top: border.frame = CGRect(x: 0, y: 0, width: frame.size.width, height: width) borderTop?.removeFromSuperlayer() borderTop = border borderTopWidth = width case .Right: border.frame = CGRect(x: frame.size.width - width, y: 0, width: width, height: frame.size.height) borderRight?.removeFromSuperlayer() borderRight = border borderRightWidth = width case .Bottom: border.frame = CGRect(x: 0, y: frame.size.height - width, width: frame.size.width, height: width) borderBottom?.removeFromSuperlayer() borderBottom = border borderBottomWidth = width case .Left: border.frame = CGRect(x: 0, y: 0, width: width, height: frame.size.height) borderLeft?.removeFromSuperlayer() borderLeft = border borderLeftWidth = width } layer.addSublayer(border) } override func layoutSubviews() { super.layoutSubviews() borderTop?.frame = CGRect(x: 0, y: 0, width: frame.size.width, height: borderTopWidth!) borderRight?.frame = CGRect(x: frame.size.width - borderRightWidth!, y: 0, width: borderRightWidth!, height: frame.size.height) borderBottom?.frame = CGRect(x: 0, y: frame.size.height - borderBottomWidth!, width: frame.size.width, height: borderBottomWidth!) borderLeft?.frame = CGRect(x: 0, y: 0, width: borderLeftWidth!, height: frame.size.height) } }


En lugar de usar un UIView , como lo sugiere @ ImreKelényi, puede usar un CALayer :

// Add a bottomBorder. CALayer *bottomBorder = [CALayer layer]; bottomBorder.frame = CGRectMake(0.0f, 43.0f, toScrollView.frame.size.width, 1.0f); bottomBorder.backgroundColor = [UIColor colorWithWhite:0.8f alpha:1.0f].CGColor; [toScrollView.layer addSublayer:bottomBorder];


Escribí un método general que agregará un borde en los lados que desee en cualquier UIView . Puede definir grosor, color, márgenes y orden zOrder para cada lado.

/* view: the view to draw border around thickness: thickness of the border on the given side color: color of the border on the given side margin: space between the border''s outer edge and the view''s frame edge on the given side. zOrder: defines the order to add the borders to the view. The borders will be added by zOrder from lowest to highest, thus making the highest priority border visible when two borders overlap at the corners. */ +(void) drawBorderAroundUIView:(UIView *) view thicknessLeft:(CGFloat) thicknessLeft colorLeft:(UIColor *)colorLeft marginLeft:(CGFloat) marginLeft zOrderLeft:(int) zOrderLeft thicknessRight:(CGFloat) thicknessRight colorRight:(UIColor *)colorRight marginRight:(CGFloat) marginRight zOrderRight:(int) zOrderRight thicknessTop:(CGFloat) thicknessTop colorTop:(UIColor *)colorTop marginTop:(CGFloat) marginTop zOrderTop:(int) zOrderTop thicknessBottom:(CGFloat) thicknessBottom colorBottom:(UIColor *)colorBottom marginBottom:(CGFloat) marginBottom zOrderBottom:(int) zOrderBottom{ //make margins be the outside edge and make positive margin represent a smaller rectangle marginBottom = -1 * marginBottom - thicknessBottom; marginTop = -1 * marginTop - thicknessTop; marginLeft = -1 * marginLeft - thicknessLeft; marginRight = -1 * marginRight - thicknessRight; //get reference points for corners CGPoint upperLeftCorner = CGPointZero; CGPoint lowerLeftCorner = CGPointMake(upperLeftCorner.x, upperLeftCorner.y + view.frame.size.height); CGPoint upperRightCorner = CGPointMake(upperLeftCorner.x + view.frame.size.width, upperLeftCorner.y); //left CALayer *leftBorder = [CALayer layer]; leftBorder.frame = CGRectMake(upperLeftCorner.x - thicknessLeft - marginLeft, upperLeftCorner.y - thicknessTop - marginTop, thicknessLeft, view.frame.size.height + marginTop + marginBottom + thicknessBottom + thicknessTop); leftBorder.backgroundColor = colorLeft.CGColor; //right CALayer *rightBorder = [CALayer layer]; rightBorder.frame = CGRectMake(upperRightCorner.x + marginRight, upperRightCorner.y - thicknessTop - marginTop, thicknessRight, view.frame.size.height + marginTop + marginBottom + thicknessBottom + thicknessTop); rightBorder.backgroundColor = colorRight.CGColor; //top CALayer *topBorder = [CALayer layer]; topBorder.frame = CGRectMake(upperLeftCorner.x - thicknessLeft - marginLeft, upperLeftCorner.y - thicknessTop - marginTop, view.frame.size.width + marginLeft + marginRight + thicknessLeft + thicknessRight, thicknessTop); topBorder.backgroundColor = colorTop.CGColor; //bottom CALayer *bottomBorder = [CALayer layer]; bottomBorder.frame = CGRectMake(upperLeftCorner.x - thicknessLeft - marginLeft, lowerLeftCorner.y + marginBottom, view.frame.size.width + marginLeft + marginRight + thicknessLeft + thicknessRight, thicknessBottom); bottomBorder.backgroundColor = colorBottom.CGColor; //define dictionary keys to be used for adding borders in order of zOrder NSString *borderDK = @"border"; NSString *zOrderDK = @"zOrder"; //storing borders in dictionaries in preparation to add them in order of zOrder NSDictionary *leftBorderDictionary = [NSDictionary dictionaryWithObjectsAndKeys:leftBorder, borderDK, [NSNumber numberWithInt:zOrderLeft], zOrderDK, nil]; NSDictionary *rightBorderDictionary = [NSDictionary dictionaryWithObjectsAndKeys:rightBorder, borderDK, [NSNumber numberWithInt:zOrderRight], zOrderDK, nil]; NSDictionary *topBorderDictionary = [NSDictionary dictionaryWithObjectsAndKeys:topBorder, borderDK, [NSNumber numberWithInt:zOrderTop], zOrderDK, nil]; NSDictionary *bottomBorderDictionary = [NSDictionary dictionaryWithObjectsAndKeys:bottomBorder, borderDK, [NSNumber numberWithInt:zOrderBottom], zOrderDK, nil]; NSMutableArray *borders = [NSMutableArray arrayWithObjects:leftBorderDictionary, rightBorderDictionary, topBorderDictionary, bottomBorderDictionary, nil]; //add borders in order of zOrder (lowest -> highest). Thus the highest zOrder will be added last so it will be on top. while (borders.count) { //look for the next lowest zOrder border to add NSDictionary *nextBorderToLayDown = [borders objectAtIndex:0]; for (int indexOfBorder = 0; indexOfBorder < borders.count; indexOfBorder++) { NSDictionary *borderAtIndex = [borders objectAtIndex:indexOfBorder]; if ([[borderAtIndex objectForKey:zOrderDK] intValue] < [[nextBorderToLayDown objectForKey:zOrderDK] intValue]) { nextBorderToLayDown = borderAtIndex; } } //add the border to the view [view.layer addSublayer:[nextBorderToLayDown objectForKey:borderDK]]; [borders removeObject:nextBorderToLayDown]; } }


Implementado en una categoría:

UIButton + Border.h:

@interface UIButton (Border) - (void)addBottomBorderWithColor: (UIColor *) color andWidth:(CGFloat) borderWidth; - (void)addLeftBorderWithColor: (UIColor *) color andWidth:(CGFloat) borderWidth; - (void)addRightBorderWithColor: (UIColor *) color andWidth:(CGFloat) borderWidth; - (void)addTopBorderWithColor: (UIColor *) color andWidth:(CGFloat) borderWidth; @end

UIButton + Border.m:

@implementation UIButton (Border) - (void)addTopBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth { CALayer *border = [CALayer layer]; border.backgroundColor = color.CGColor; border.frame = CGRectMake(0, 0, self.frame.size.width, borderWidth); [self.layer addSublayer:border]; } - (void)addBottomBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth { CALayer *border = [CALayer layer]; border.backgroundColor = color.CGColor; border.frame = CGRectMake(0, self.frame.size.height - borderWidth, self.frame.size.width, borderWidth); [self.layer addSublayer:border]; } - (void)addLeftBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth { CALayer *border = [CALayer layer]; border.backgroundColor = color.CGColor; border.frame = CGRectMake(0, 0, borderWidth, self.frame.size.height); [self.layer addSublayer:border]; } - (void)addRightBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth { CALayer *border = [CALayer layer]; border.backgroundColor = color.CGColor; border.frame = CGRectMake(self.frame.size.width - borderWidth, 0, borderWidth, self.frame.size.height); [self.layer addSublayer:border]; }

¡Espero eso ayude!


La respuesta más completa. https://github.com/oney/UIView-Border

let rectangle = UIView(frame: CGRect(x: 100, y: 100, width: 100, height: 60)) rectangle.backgroundColor = UIColor.grayColor() view.addSubview(rectangle) rectangle.borderTop = Border(size: 3, color: UIColor.orangeColor(), offset: UIEdgeInsets(top: 0, left: -10, bottom: 0, right: -5)) rectangle.borderBottom = Border(size: 6, color: UIColor.redColor(), offset: UIEdgeInsets(top: 0, left: 10, bottom: 10, right: 0)) rectangle.borderLeft = Border(size: 2, color: UIColor.blueColor(), offset: UIEdgeInsets(top: 10, left: -10, bottom: 0, right: 0)) rectangle.borderRight = Border(size: 2, color: UIColor.greenColor(), offset: UIEdgeInsets(top: 10, left: 10, bottom: 0, right: 0))


No es necesario que agregue una capa para cada borde, solo use una ruta bezier para dibujarlos una vez.

CGRect rect = self.bounds; CGPoint destPoint[4] = {CGPointZero, (CGPoint){0, rect.size.height}, (CGPoint){rect.size.width, rect.size.height}, (CGPoint){rect.size.width, 0}}; BOOL position[4] = {_top, _left, _bottom, _right}; UIBezierPath *path = [UIBezierPath new]; [path moveToPoint:destPoint[3]]; for (int i = 0; i < 4; ++i) { if (position[i]) { [path addLineToPoint:destPoint[i]]; } else { [path moveToPoint:destPoint[i]]; } } CAShapeLayer *borderLayer = [CAShapeLayer new]; borderLayer.frame = self.bounds; borderLayer.path = path.CGPath; borderLayer.lineWidth = _borderWidth ?: 1 / [UIScreen mainScreen].scale; borderLayer.strokeColor = _borderColor.CGColor; borderLayer.fillColor = [UIColor clearColor].CGColor; [self.layer addSublayer:borderLayer];


O bien, la forma más fácil de usar es sobrecargar DrawRect, simplemente así:

@interface TPActionSheetButton : UIButton @property (assign) BOOL drawsTopLine; @property (assign) BOOL drawsBottomLine; @property (assign) BOOL drawsRightLine; @property (assign) BOOL drawsLeftLine; @property (strong, nonatomic) UIColor * lineColor; @end @implementation TPActionSheetButton - (void) drawRect:(CGRect)rect { CGContextRef ctx = UIGraphicsGetCurrentContext(); CGContextSetLineWidth(ctx, 0.5f * [[UIScreen mainScreen] scale]); CGFloat red, green, blue, alpha; [self.lineColor getRed:&red green:&green blue:&blue alpha:&alpha]; CGContextSetRGBStrokeColor(ctx, red, green, blue, alpha); if(self.drawsTopLine) { CGContextBeginPath(ctx); CGContextMoveToPoint(ctx, CGRectGetMinX(rect), CGRectGetMinY(rect)); CGContextAddLineToPoint(ctx, CGRectGetMaxX(rect), CGRectGetMinY(rect)); CGContextStrokePath(ctx); } if(self.drawsBottomLine) { CGContextBeginPath(ctx); CGContextMoveToPoint(ctx, CGRectGetMinX(rect), CGRectGetMaxY(rect)); CGContextAddLineToPoint(ctx, CGRectGetMaxX(rect), CGRectGetMaxY(rect)); CGContextStrokePath(ctx); } if(self.drawsLeftLine) { CGContextBeginPath(ctx); CGContextMoveToPoint(ctx, CGRectGetMinX(rect), CGRectGetMinY(rect)); CGContextAddLineToPoint(ctx, CGRectGetMinX(rect), CGRectGetMaxY(rect)); CGContextStrokePath(ctx); } if(self.drawsRightLine) { CGContextBeginPath(ctx); CGContextMoveToPoint(ctx, CGRectGetMaxX(rect), CGRectGetMinY(rect)); CGContextAddLineToPoint(ctx, CGRectGetMaxX(rect), CGRectGetMaxY(rect)); CGContextStrokePath(ctx); } [super drawRect:rect]; } @end


Puede agregar una vista independiente UIView con 1 punto de altura y color de fondo gris a self.view y self.view justo debajo toScrollView .

EDITAR: a menos que tenga una buena razón (desea usar algunos servicios de UIView que no son ofrecidos por CALayer), debe usar CALayer como sugiere @MattDiPasquale . UIView tiene una sobrecarga mayor, lo que podría no ser un problema en la mayoría de los casos, pero aún así, la otra solución es más elegante.


Si necesita una solución realmente adaptable (para todos los tamaños de pantalla), entonces este es:

/** * Extends UIView with shortcut methods * * @author Alexander Volkov * @version 1.0 */ extension UIView { /** Adds bottom border to the view with given side margins - parameter color: the border color - parameter margins: the left and right margin */ func addBottomBorder(color: UIColor = UIColor.lightBorderColor(), margins: CGFloat = 0) { let border = UIView() border.backgroundColor = color border.translatesAutoresizingMaskIntoConstraints = false self.addSubview(border) border.addConstraint(NSLayoutConstraint(item: border, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.Height, multiplier: 1, constant: 1)) self.addConstraint(NSLayoutConstraint(item: border, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 0)) self.addConstraint(NSLayoutConstraint(item: border, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.Leading, multiplier: 1, constant: margins)) self.addConstraint(NSLayoutConstraint(item: border, attribute: NSLayoutAttribute.Trailing, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.Trailing, multiplier: 1, constant: margins)) } }


Swift 3 versión de la respuesta de Confile:

import UIKit extension UIView { func addTopBorderWithColor(color: UIColor, width: CGFloat) { let border = CALayer() border.backgroundColor = color.cgColor border.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: width) self.layer.addSublayer(border) } func addRightBorderWithColor(color: UIColor, width: CGFloat) { let border = CALayer() border.backgroundColor = color.cgColor border.frame = CGRect(x: self.frame.size.width - width, y: 0, width: width, height: self.frame.size.height) self.layer.addSublayer(border) } func addBottomBorderWithColor(color: UIColor, width: CGFloat) { let border = CALayer() border.backgroundColor = color.cgColor border.frame = CGRect(x: 0, y: self.frame.size.height - width, width: self.frame.size.width, height: width) self.layer.addSublayer(border) } func addLeftBorderWithColor(color: UIColor, width: CGFloat) { let border = CALayer() border.backgroundColor = color.cgColor border.frame = CGRect(x: 0, y: 0, width: width, height: self.frame.size.height) self.layer.addSublayer(border) } }

Uso cuando se utiliza el diseño automático:

class CustomView: UIView { override func awakeFromNib() { super.awakeFromNib() } override func layoutSubviews() { addBottomBorderWithColor(color: UIColor.white, width: 1) } }


También hay un código mejorado con la función Eliminar borde. Basado en una respuesta confusa .

import UIKit enum viewBorder: String { case Left = "borderLeft" case Right = "borderRight" case Top = "borderTop" case Bottom = "borderBottom" } extension UIView { func addBorder(vBorder: viewBorder, color: UIColor, width: CGFloat) { let border = CALayer() border.backgroundColor = color.CGColor border.name = vBorder.rawValue switch vBorder { case .Left: border.frame = CGRectMake(0, 0, width, self.frame.size.height) case .Right: border.frame = CGRectMake(self.frame.size.width - width, 0, width, self.frame.size.height) case .Top: border.frame = CGRectMake(0, 0, self.frame.size.width, width) case .Bottom: border.frame = CGRectMake(0, self.frame.size.height - width, self.frame.size.width, width) } self.layer.addSublayer(border) } func removeBorder(border: viewBorder) { var layerForRemove: CALayer? for layer in self.layer.sublayers! { if layer.name == border.rawValue { layerForRemove = layer } } if let layer = layerForRemove { layer.removeFromSuperlayer() } } }

Actualización: Swift 3

import UIKit enum ViewBorder: String { case left, right, top, bottom } extension UIView { func add(border: ViewBorder, color: UIColor, width: CGFloat) { let borderLayer = CALayer() borderLayer.backgroundColor = color.cgColor borderLayer.name = border.rawValue switch border { case .left: borderLayer.frame = CGRect(x: 0, y: 0, width: width, height: self.frame.size.height) case .right: borderLayer.frame = CGRect(x: self.frame.size.width - width, y: 0, width: width, height: self.frame.size.height) case .top: borderLayer.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: width) case .bottom: borderLayer.frame = CGRect(x: 0, y: self.frame.size.height - width, width: self.frame.size.width, height: width) } self.layer.addSublayer(borderLayer) } func remove(border: ViewBorder) { guard let sublayers = self.layer.sublayers else { return } var layerForRemove: CALayer? for layer in sublayers { if layer.name == border.rawValue { layerForRemove = layer } } if let layer = layerForRemove { layer.removeFromSuperlayer() } } }


Rápido

Crear la extensión UIView

private var bottomLineColorAssociatedKey : UIColor = .black private var topLineColorAssociatedKey : UIColor = .black private var rightLineColorAssociatedKey : UIColor = .black private var leftLineColorAssociatedKey : UIColor = .black extension UIView { @IBInspectable var bottomLineColor: UIColor { get { if let color = objc_getAssociatedObject(self, &bottomLineColorAssociatedKey) as? UIColor { return color } else { return .black } } set { objc_setAssociatedObject(self, &bottomLineColorAssociatedKey, newValue, .OBJC_ASSOCIATION_RETAIN) } } @IBInspectable var bottomLineWidth: CGFloat { get { return self.bottomLineWidth } set { DispatchQueue.main.async { self.addBottomBorderWithColor(color: self.bottomLineColor, width: newValue) } } } @IBInspectable var topLineColor: UIColor { get { if let color = objc_getAssociatedObject(self, &topLineColorAssociatedKey) as? UIColor { return color } else { return .black } } set { objc_setAssociatedObject(self, &topLineColorAssociatedKey, newValue, .OBJC_ASSOCIATION_RETAIN) } } @IBInspectable var topLineWidth: CGFloat { get { return self.topLineWidth } set { DispatchQueue.main.async { self.addTopBorderWithColor(color: self.topLineColor, width: newValue) } } } @IBInspectable var rightLineColor: UIColor { get { if let color = objc_getAssociatedObject(self, &rightLineColorAssociatedKey) as? UIColor { return color } else { return .black } } set { objc_setAssociatedObject(self, &rightLineColorAssociatedKey, newValue, .OBJC_ASSOCIATION_RETAIN) } } @IBInspectable var rightLineWidth: CGFloat { get { return self.rightLineWidth } set { DispatchQueue.main.async { self.addRightBorderWithColor(color: self.rightLineColor, width: newValue) } } } @IBInspectable var leftLineColor: UIColor { get { if let color = objc_getAssociatedObject(self, &leftLineColorAssociatedKey) as? UIColor { return color } else { return .black } } set { objc_setAssociatedObject(self, &leftLineColorAssociatedKey, newValue, .OBJC_ASSOCIATION_RETAIN) } } @IBInspectable var leftLineWidth: CGFloat { get { return self.leftLineWidth } set { DispatchQueue.main.async { self.addLeftBorderWithColor(color: self.leftLineColor, width: newValue) } } } func addTopBorderWithColor(color: UIColor, width: CGFloat) { let border = CALayer() border.name = "topBorderLayer" removePreviouslyAddedLayer(name: border.name ?? "") border.backgroundColor = color.cgColor border.frame = CGRect(x: 0, y : 0,width: self.frame.size.width, height: width) self.layer.addSublayer(border) } func addRightBorderWithColor(color: UIColor, width: CGFloat) { let border = CALayer() border.name = "rightBorderLayer" removePreviouslyAddedLayer(name: border.name ?? "") border.backgroundColor = color.cgColor border.frame = CGRect(x: self.frame.size.width - width, y: 0, width : width, height :self.frame.size.height) self.layer.addSublayer(border) } func addBottomBorderWithColor(color: UIColor, width: CGFloat) { let border = CALayer() border.name = "bottomBorderLayer" removePreviouslyAddedLayer(name: border.name ?? "") border.backgroundColor = color.cgColor border.frame = CGRect(x: 0, y: self.frame.size.height - width,width : self.frame.size.width,height: width) self.layer.addSublayer(border) } func addLeftBorderWithColor(color: UIColor, width: CGFloat) { let border = CALayer() border.name = "leftBorderLayer" removePreviouslyAddedLayer(name: border.name ?? "") border.backgroundColor = color.cgColor border.frame = CGRect(x:0, y:0,width : width, height : self.frame.size.height) self.layer.addSublayer(border) } func removePreviouslyAddedLayer(name : String) { if self.layer.sublayers?.count ?? 0 > 0 { self.layer.sublayers?.forEach { if $0.name == name { $0.removeFromSuperlayer() } } } } }

C objetivo

Crear clase de categoría de UIView

UIView + Border.h

#import <UIKit/UIKit.h> #import <Foundation/Foundation.h> @interface UIView (Border) @property (nonatomic) IBInspectable UIColor *topLineColor; @property (nonatomic) IBInspectable CGFloat topLineWidth; @property (nonatomic) IBInspectable UIColor *bottomLineColor; @property (nonatomic) IBInspectable CGFloat bottomLineWidth; @property (nonatomic) IBInspectable UIColor *rightLineColor; @property (nonatomic) IBInspectable CGFloat rightLineWidth; @property (nonatomic) IBInspectable UIColor *leftLineColor; @property (nonatomic) IBInspectable CGFloat leftLineWidth; - (void)addBottomBorderWithColor: (UIColor *) color andWidth:(CGFloat) borderWidth; - (void)addLeftBorderWithColor: (UIColor *) color andWidth:(CGFloat) borderWidth; - (void)addRightBorderWithColor: (UIColor *) color andWidth:(CGFloat) borderWidth; - (void)addTopBorderWithColor: (UIColor *) color andWidth:(CGFloat) borderWidth; @end

UIView + Border.m

#import "UIView+Utility.h" #import <objc/runtime.h> static char bottomLineColorKey,topLineColorKey,rightLineColorKey,leftLineColorKey; @implementation UIView(Border) @dynamic bottomLineWidth,topLineWidth,rightLineWidth,leftLineWidth; // for Bottom Line - (UIColor *)bottomLineColor { return objc_getAssociatedObject(self, &bottomLineColorKey); } - (void)setBottomLineColor:(UIColor *)bottomLineColor { objc_setAssociatedObject(self, &bottomLineColorKey, bottomLineColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } -(void)setBottomLineWidth:(CGFloat)bottomLineWidth { dispatch_async(dispatch_get_main_queue(), ^{ [self addBottomBorderWithColor:[self bottomLineColor] andWidth:bottomLineWidth]; }); } // for top Line - (UIColor *)topLineColor { return objc_getAssociatedObject(self, &topLineColorKey); } - (void)setTopLineColor:(UIColor *)topLineColor { objc_setAssociatedObject(self, &topLineColorKey, topLineColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (void)setTopLineWidth:(CGFloat)topLineWidth{ dispatch_async(dispatch_get_main_queue(), ^{ [self addTopBorderWithColor:[self topLineColor] andWidth:topLineWidth]; }); } // for right Line - (UIColor *)rightLineColor { return objc_getAssociatedObject(self, &rightLineColorKey); } -(void)setRightLineColor:(UIColor *)rightLineColor { objc_setAssociatedObject(self, &rightLineColorKey, rightLineColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } -(void)setRightLineWidth:(CGFloat)rightLineWidth{ dispatch_async(dispatch_get_main_queue(), ^{ [self addRightBorderWithColor:[self rightLineColor] andWidth:rightLineWidth]; }); } // for left Line -(UIColor *)leftLineColor { return objc_getAssociatedObject(self, &leftLineColorKey); } -(void)setLeftLineColor:(UIColor *)leftLineColor{ objc_setAssociatedObject(self, &leftLineColorKey, leftLineColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } -(void)setLeftLineWidth:(CGFloat)leftLineWidth{ dispatch_async(dispatch_get_main_queue(), ^{ [self addLeftBorderWithColor:[self leftLineColor] andWidth:leftLineWidth]; }); } - (void)addTopBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth { CALayer *border = [CALayer layer]; border.name = @"topBorderLayer"; [self removePreviouslyAddedLayer:border.name]; border.backgroundColor = color.CGColor; border.frame = CGRectMake(0, 0, self.frame.size.width, borderWidth); [self.layer addSublayer:border]; } - (void)addBottomBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth { CALayer *border = [CALayer layer]; border.name = @"bottomBorderLayer"; [self removePreviouslyAddedLayer:border.name]; border.backgroundColor = color.CGColor; border.frame = CGRectMake(0, self.frame.size.height - borderWidth, self.frame.size.width, borderWidth); [self.layer addSublayer:border]; } - (void)addLeftBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth { CALayer *border = [CALayer layer]; border.name = @"leftBorderLayer"; [self removePreviouslyAddedLayer:border.name]; border.backgroundColor = color.CGColor; border.frame = CGRectMake(0, 0, borderWidth, self.frame.size.height); [self.layer addSublayer:border]; } - (void)addRightBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth { CALayer *border = [CALayer layer]; border.name = @"rightBorderLayer"; [self removePreviouslyAddedLayer:border.name]; border.backgroundColor = color.CGColor; border.frame = CGRectMake(self.frame.size.width - borderWidth, 0, borderWidth, self.frame.size.height); [self.layer addSublayer:border]; } - (void)removePreviouslyAddedLayer:(NSString *)name { if (self.layer.sublayers.count > 0) { for (CALayer *layer in self.layer.sublayers) { if ([layer.name isEqualToString:name]) { [layer removeFromSuperlayer]; } } } } @end

Uso: - Seleccione cualquier control del guión gráfico, luego muestre el inspector de atributos (lado derecho) Verá la imagen siguiente Ejemplo. (Nota: el borde solo aparece en tiempo de ejecución).

Ahora puede establecer cualquier lado del color y el ancho del borde.


Swift 4/3

Puedes usar esta solución debajo. Funciona en UIBezierPaths que son más livianos que las capas, lo que provoca tiempos de inicio rápidos. Es fácil de usar, mira las instrucciones a continuación.

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

  1. Establezca la clase de UIView en ResizeBorderView
  2. Establezca el color y el ancho de línea usando yourview.color y yourview.lineWidth en su método viewDidAppear
  3. Establezca los bordes, por ejemplo: yourview.edges = [.right, .left] ([.all]) para todos
  4. Disfrute de inicio rápido y redimensionamiento de bordes