我的问题是题目。
我不知道如何添加一个边框在一个特定的一面,顶部或底部,任何一面..。 layer.border为整个视图绘制边界..。
layer.border
子类 UIView并在子类中实现 drawRect:,例如:
UIView
drawRect:
目标 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() }
这将绘制一条2像素的红线作为顶部边框。您提到的所有其他变体都作为一个琐碎的练习留给读者。
推荐使用石英2D 编程指南 。
这是一个简单的解决方案。在 UIView上添加一个标签,清除标签上的文本,并将标签背景颜色设置为边框颜色。将标签的原点 (x,y)设置为视图的原点 (x,y)。并将标签的宽度设置为 UIView的宽度,将高度设置为1或2(对于 UIView顶部的边框高度)。这样应该就行了。
(x,y)
在 viewDidLoad 中使用以下代码
- (void)viewDidLoad { [super viewDidLoad]; [self.view.layer setBorderWidth: 1.0]; [self.view.layer setCornerRadius:8.0f]; [self.view.layer setMasksToBounds:YES]; [self.view.layer setBorderColor:[[UIColor colorWithRed:251.0f/255.0f green:185.0f/255.0f blue:23.0f/255.0f alpha:1.0f]];` }
此代码将红色边框设置为视图
基于 NSBum 的的答案,我采用了一个类似的方法,创建了这个简单的 UIView 子类,这样它就可以在 Interface Builder 中工作,并且带有约束: Github 链接 通过使用 CGContextFillRect 而不是 CGContextStrokePath,我可以预测地保持线条完全固定,并且在视图的边界内。
以下是我的博客文章: Http://natrosoft.com/?p=55
基本上只需要在 Interface Builder 中输入一个 UIView,然后将它的类类型改为 NAUiViewWithBorders。 然后在你的 VC 的视图中,做一些像:
/* 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];
这里有一个到 。 m 文件的直接链接,您可以看到它的实现。 也有一个演示项目。希望这对某人有所帮助:)
就个人而言,我喜欢 view + drarect 的子分类,但这里只是另一种方式来处理它(它的工作原理与@If Pollavith 接受的答案相同) :
可以将新的边框层设置为具有您喜欢的任何尺寸。因此,就像“ If Pollavith 的回答”一样,你创建了一个图层,它的高度和视野的宽度都是你想要的。使用图层的框架定义将其放置在您想要的位置,然后将其作为子层添加到您的视图中。
作为参考,我自己的要求是在视图的左手边放置一个边框(请不要剪切和粘贴这段代码,dis’me 只是因为它没有在视图的顶部放置边框——修改下面的代码非常简单) :
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];
我想,对于这个问题,制作一个小的 UIView 或 UILabel,唯一适度的好处就是 CALayer 被认为是“更轻量级”的,并且有很多有趣的观点(如观点)关于重写 Drarect 和使用 CALayers (如这里: IOS: 使用 UIView 与其层的拖延层: inContext:)。
我喜欢蓝色。
我在这里考虑子类化 UIView和覆盖 drawRect过度杀伤。为什么不在 UIView上添加一个扩展并添加边界子视图?
drawRect
@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
有了这段代码,你就不用再绑定到你的子类了,你可以把它应用到任何继承自 UIView的东西上——在你的项目中可以重用,或者其他任何东西。传递其他参数到您的方法中,以定义其他颜色和宽度。有很多选择。
选定答案的代码,以防有人需要。
注意: 这不适用于自动布局(又名,旋转设备到景观等)。
首先定义一个厚度:
NSInteger borderThickness = 1;
然后复制使用任意或所有这些来设置您想要设置的边框。
顶部边界
UIView *topBorder = [UIView new]; topBorder.backgroundColor = [UIColor lightGrayColor]; topBorder.frame = CGRectMake(0, 0, myView.frame.size.width, borderThickness); [myView addSubview:topBorder];
底部边界
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];
左边界
UIView *leftBorder = [UIView new]; leftBorder.backgroundColor = [UIColor lightGrayColor]; leftBorder.frame = CGRectMake(0, 0, borderThickness, myView.frame.size.height); [myView addSubview:leftBorder];
右边界
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];
我对一个类似问题的回答是: https://stackoverflow.com/a/27141956/435766 我个人更喜欢沿着这条分类之路前进,因为我希望能够在 UIView 的任何子类上使用它。
对我来说,最好的方法是在 UIView 上分类,但是用 adding views代替 CALayers,所以我们可以用 take advantage of AutoresizingMasks来确保边框随着视图一起调整大小。
adding views
take advantage of AutoresizingMasks
目标 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) }
快速版:
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)
编辑: 更新版本请点击这里查看我的回购: Https://github.com/goktugyil/ezswiftextensions/blob/master/sources/uiviewextensions.swift
看看 addBorder 部分
如果我从情节串连板内部构建,我更喜欢在我有用的 UIView后面添加一个 UIView... 如果我想在我的 UIView顶部创建一个边框,我只需要增加背景 UIView的高度通过我的边框宽度。.其他任何一方也可以这样做:)
增加了圆角的能力到 Adam Waite 的原帖,和多重编辑
重要提示! : 不要忘记在调用前面注释的“ addorders”之前添加“ label.layoutIfNeeded ()”
注意: 我只在 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 y = cornerRadius var startAngle: CGFloat = .pi; var endAngle: CGFloat = .pi*3/2 switch corner { case .bottomLeft: y = height - cornerRadius startAngle = .pi/2; endAngle = .pi case .bottomRight: x = width - cornerRadius y = height - 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: y), 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) } }
我把 Adam Waite 和 Paul 的答案结合起来。我还添加了将选定的边连接在一起的可能性,所以您只需要像下面这样调用一个函数:
[self.view addBordersToEdge:(UIRectEdgeLeft|UIRectEdgeRight) withColor:[UIColor grayColor] andWidth:1.0];
大约是这样:
[self.view addBordersToEdge:(UIRectEdgeAll) withColor:[UIColor grayColor] andWidth:1.0];
您需要实现的是 UIView 上的一个类别,正如其他答案中所建议的那样,具体实现如下:
- (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]; } }
除此之外,N8tr还可以添加一个可用性,从情节串连板设置它们: - 在.h 文件中添加两个属性,如 borderColor和 borderWidth; 然后你可以在情节串连图板中添加 keyPaths,参见链接到截图
borderColor
borderWidth
keyPaths
只是在这里张贴,以帮助有人寻找添加边界。我已经做了一些改变,在这里接受的答案 快速标签只剩下边框。 改变宽度的情况下 UIRectEdge.Top从 CGRectGetHeight(self.frame)到 CGRectGetWidth(self.frame)和情况下 UIRectEdge.Bottom从 UIScreen.mainScreen().bounds.width到 CGRectGetWidth(self.frame),以获得正确的边界。使用 Swift 2。
UIRectEdge.Top
CGRectGetHeight(self.frame)
CGRectGetWidth(self.frame)
UIRectEdge.Bottom
UIScreen.mainScreen().bounds.width
最后一个扩展是:
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) } }
将 DanShev答案转换为 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) } }
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) } }
您还可以检查这个 UIKit 和 Foundation 类别的集合: https://github.com/leszek-s/LSCategories
它允许用一行代码在 UIView 的一侧添加边框:
[self.someView lsAddBorderOnEdge:UIRectEdgeTop color:[UIColor blueColor] width:2];
它可以正确地处理视图旋转,而这里发布的大多数答案并不能很好地处理它。
对于 C # 中的 Xamarin,我只是在添加子层时内联创建边框
View.Layer.AddSublayer(new CALayer() { BackgroundColor = UIColor.Black.CGColor, Frame = new CGRect(0, 0, View.Frame.Width, 0.5f) });
您可以按照其他人的建议,对底部、左侧和右侧边框进行排列。
这是个老问题了,但是带有运行时边界调整的自动布局解决方案仍然缺失。
borders(for: [.left, .bottom], width: 2, color: .red)
下面的 UIView 扩展将只在给定的边上添加边框。如果在运行时更改边缘,则边框将相应地进行调整。
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])) } } } } }
注意: 这里的大多数解决方案是不适应的,也不会调整大小。将调整大小的解决方案将对 巨大的启动时间产生影响,因为它们使用大量 CPU。
您可以在下面使用此解决方案。它工作在比层更轻的 UIBezierPath 上,导致快速启动时间。它很容易使用,请看下面的说明。
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() } } }
以防有人需要 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); } }
//MARK:-添加左边框供查看
(void)prefix_addLeftBorder:(UIView *) viewName { CALayer *leftBorder = [CALayer layer]; leftBorder.backgroundColor = [UIColor colorWithRed:221/255.0f green:221/255.0f blue:221/255.0f alpha:1.0f].CGColor; leftBorder.frame = CGRectMake(0,0,1.0,viewName.frame.size.height); [viewName.layer addSublayer:leftBorder]; }
//MARK:-添加右边框供查看
(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:-添加底部边框以便查看
(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]; }
用于在 Swift 中为 UIView 设置顶部边框和底部边框。
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)
在 Swift 4和3中
let borderThickness = 2 let topBorder = UIView() topBorder.backgroundColor = UIColor.red topBorder.frame = CGRect(x: 0, y: 0, width: Int(yourViewFromOutlet.frame.size.width), height: borderThickness) yourViewFromOutlet.addSubview(topBorder)
这里是一个雨燕4版本的 保罗的回答
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) }
我对 Dan 的回答做了一些修改,这样我就可以用一个命令为多个边添加边框:
infoView.addBorder(toEdges: [.left, .bottom, .right], color: borderColor, thickness: 1)
完整代码如下:
extension UIView { func addBorder(toEdges edges: UIRectEdge, color: UIColor, thickness: CGFloat) { func addBorder(toEdge edges: UIRectEdge, color: UIColor, thickness: CGFloat) { let border = CALayer() border.backgroundColor = color.cgColor switch edges { case .top: border.frame = CGRect(x: 0, y: 0, width: frame.width, height: thickness) case .bottom: border.frame = CGRect(x: 0, y: frame.height - thickness, width: frame.width, height: thickness) case .left: border.frame = CGRect(x: 0, y: 0, width: thickness, height: frame.height) case .right: border.frame = CGRect(x: frame.width - thickness, y: 0, width: thickness, height: frame.height) default: break } layer.addSublayer(border) } if edges.contains(.top) || edges.contains(.all) { addBorder(toEdge: .top, color: color, thickness: thickness) } if edges.contains(.bottom) || edges.contains(.all) { addBorder(toEdge: .bottom, color: color, thickness: thickness) } if edges.contains(.left) || edges.contains(.all) { addBorder(toEdge: .left, color: color, thickness: thickness) } if edges.contains(.right) || edges.contains(.all) { addBorder(toEdge: .right, color: color, thickness: thickness) } } }
我想出了一个解决方案,使用 Swift 4.1,使用 AutoLayout和 UIViews,以便它将随着视图调整大小。
AutoLayout
UIViews
它基于@AdamWaite 的回答,但是解决了表格视图单元格的重用问题。如果在添加新边框之前没有删除以前的边框,那么重用的单元格将包含多个边框。
这可以通过创建一个虚拟的 BorderView 类并在子视图中搜索边框并删除它们来解决。
此代码使用 SnapKit作为约束,使用 CocoaLumberjack作为调试。如果您不使用这些,那么转换应该相当简单
SnapKit
CocoaLumberjack
class BorderView: UIView { } extension UIView { private func addSidedBorder(toEdge edge: UIRectEdge, withColor color: UIColor, inset: CGFloat, thickness: CGFloat) { let border = BorderView(frame: .zero) border.backgroundColor = color addSubview(border) border.snp.makeConstraints { make in switch edge { case .top: make.top.equalToSuperview() make.height.equalTo(thickness) make.left.right.equalToSuperview().inset(inset) case .left: make.left.equalToSuperview() make.width.equalTo(thickness) make.top.bottom.equalToSuperview().inset(inset) case .bottom: make.bottom.equalToSuperview() make.height.equalTo(thickness) make.left.right.equalToSuperview().inset(inset) case .right: make.right.equalToSuperview() make.width.equalTo(thickness) make.top.bottom.equalToSuperview().inset(inset) default: DDLogWarn("Invalid sided border given in ExtendedUIView, border not added correctly") } } } func addBorder(toEdge edge: UIRectEdge, withColor color: UIColor = .black, inset: CGFloat = 0.0, thickness: CGFloat = 1.0) { // Remove existing borders from view and readd them for view in subviews { if view is BorderView { view.removeFromSuperview() } } if edge.contains(.all) { addSidedBorder(toEdge: .top, withColor: color, inset: inset, thickness: thickness) addSidedBorder(toEdge: .left, withColor: color, inset: inset, thickness: thickness) addSidedBorder(toEdge: .bottom, withColor: color, inset: inset, thickness: thickness) addSidedBorder(toEdge: .right, withColor: color, inset: inset, thickness: thickness) } else { if edge.contains(.top) { addSidedBorder(toEdge: .top, withColor: color, inset: inset, thickness: thickness) } if edge.contains(.left) { addSidedBorder(toEdge: .left, withColor: color, inset: inset, thickness: thickness) } if edge.contains(.bottom) { addSidedBorder(toEdge: .bottom, withColor: color, inset: inset, thickness: thickness) } if edge.contains(.right) { addSidedBorder(toEdge: .right, withColor: color, inset: inset, thickness: thickness) } } } }
添加这段代码,然后在子类 UIView中调用:
view.addBorder(toEdge: [.left, .right], withColor: .red, inset: 0.0, thickness: 1.0)
受@Addison 的启发,我在没有使用任何第三方框架的情况下重写了扩展,他使用了 SnapKit 和 CocoaLumberjack。
在@Addison 方法中,我还删除了之前添加的边框,所以这个实现应该能够很好地处理表单元格和集合单元格这样的可重用视图。
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 } }
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 } } } }
对我来说很有用
extension UIView { func addBorders(edges: UIRectEdge = .all, color: UIColor = .black, width: CGFloat = 1.0) { func createBorder() -> UIView { let borderView = UIView(frame: CGRect.zero) borderView.translatesAutoresizingMaskIntoConstraints = false borderView.backgroundColor = color return borderView } if (edges.contains(.all) || edges.contains(.top)) { let topBorder = createBorder() self.addSubview(topBorder) NSLayoutConstraint.activate([ topBorder.topAnchor.constraint(equalTo: self.topAnchor), topBorder.leadingAnchor.constraint(equalTo: self.leadingAnchor), topBorder.trailingAnchor.constraint(equalTo: self.trailingAnchor), topBorder.heightAnchor.constraint(equalToConstant: width) ]) } if (edges.contains(.all) || edges.contains(.left)) { let leftBorder = createBorder() self.addSubview(leftBorder) NSLayoutConstraint.activate([ leftBorder.topAnchor.constraint(equalTo: self.topAnchor), leftBorder.bottomAnchor.constraint(equalTo: self.bottomAnchor), leftBorder.leadingAnchor.constraint(equalTo: self.leadingAnchor), leftBorder.widthAnchor.constraint(equalToConstant: width) ]) } if (edges.contains(.all) || edges.contains(.right)) { let rightBorder = createBorder() self.addSubview(rightBorder) NSLayoutConstraint.activate([ rightBorder.topAnchor.constraint(equalTo: self.topAnchor), rightBorder.bottomAnchor.constraint(equalTo: self.bottomAnchor), rightBorder.trailingAnchor.constraint(equalTo: self.trailingAnchor), rightBorder.widthAnchor.constraint(equalToConstant: width) ]) } if (edges.contains(.all) || edges.contains(.bottom)) { let bottomBorder = createBorder() self.addSubview(bottomBorder) NSLayoutConstraint.activate([ bottomBorder.bottomAnchor.constraint(equalTo: self.bottomAnchor), bottomBorder.leadingAnchor.constraint(equalTo: self.leadingAnchor), bottomBorder.trailingAnchor.constraint(equalTo: self.trailingAnchor), bottomBorder.heightAnchor.constraint(equalToConstant: width) ]) } } }
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) } }
为了设置相应的边界,应该覆盖 视图()方法:
override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() yourView.addBorder(toSide: UIView.ViewSide.Top, withColor: UIColor.lightGray, andThickness: 1)
Swift 4.2和 AutoLayout
我浏览了所提供的解决方案,其中许多都是基于框架的 这是一个使用 AutoLayout 的简单扩展 - 使用视图代替图层,以确保我们可以使用自动布局 - 有4个约束的单一视图
使用方法如下:
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 } } }
import UIKit extension UIView { enum ViewSide { case top case left case bottom case right } func addBorders(to sides: [ViewSide], in color: UIColor, width: CGFloat) { sides.forEach { addBorder(to: $0, in: color, width: width) } } func addBorder(to side: ViewSide, in color: UIColor, width: CGFloat) { switch side { case .top: addTopBorder(in: color, width: width) case .left: addLeftBorder(in: color, width: width) case .bottom: addBottomBorder(in: color, width: width) case .right: addRightBorder(in: color, width: width) } } func addTopBorder(in color: UIColor?, width borderWidth: CGFloat) { let border = UIView() border.backgroundColor = color border.frame = CGRect(x: 0, y: 0, width: frame.size.width, height: borderWidth) border.autoresizingMask = [.flexibleWidth, .flexibleBottomMargin] addSubview(border) } func addBottomBorder(in color: UIColor?, width borderWidth: CGFloat) { let border = UIView() border.backgroundColor = color border.frame = CGRect(x: 0, y: frame.size.height - borderWidth, width: frame.size.width, height: borderWidth) border.autoresizingMask = [.flexibleWidth, .flexibleTopMargin] addSubview(border) } func addLeftBorder(in color: UIColor?, width 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(in color: UIColor?, width borderWidth: CGFloat) { let border = UIView() border.backgroundColor = color border.frame = CGRect(x: frame.size.width - borderWidth, y: 0, width: borderWidth, height: frame.size.height) border.autoresizingMask = [.flexibleHeight, .flexibleLeftMargin] addSubview(border) } }
你可以选择:
用法示例:
// Adding top border with 2 px in red let myView = UIView() myView.addBorder(to: .top, in: .red, width: 2)
(也许你可以去掉一些来自两个可用接口的模糊性,只是让 helper 方法私有化... ... 我不会把它们从那里去掉,然后把每个 case 都移到 main 方法,因为在我看来,它可能会弄乱它的主体)。