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()
}
}
}
- Establezca la clase de UIView en ResizeBorderView
- Establezca el color y el ancho de línea usando yourview.color y yourview.lineWidth en su método viewDidAppear
- Establezca los bordes, por ejemplo: yourview.edges = [.right, .left] ([.all]) para todos
- Disfrute de inicio rápido y redimensionamiento de bordes