UIView 下边框?
Posted
技术标签:
【中文标题】UIView 下边框?【英文标题】:UIView bottom border? 【发布时间】:2011-12-01 18:50:09 【问题描述】:对于UIScrollView *toScrollView
(这是屏幕的宽度),我想添加一个灰色的底部边框(与 iPhone 原生消息应用程序的撰写视图的目标字段完全相同)。
为了实现这一点,我遵循Cocoa Touch: How To Change UIView's Border Color And Thickness? 并用自定义UINavigationBar
覆盖了顶部边框,并使toScrollView
的x 坐标为-1 和宽度为322,这样左右边框就关闭了屏幕。
这看起来不错,但有点像 hack,我想知道是否有更好的方法来做到这一点。
- (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
【问题讨论】:
这是一个方便的 UIView 类别,可让您在 UIView 的任何一侧创建基于层或基于视图的边框:UIView+Borders 【参考方案1】:您可以使用CALayer
,而不是像@ImreKelényi 建议的那样使用UIView
:
// 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];
【讨论】:
别忘了#importQuartzCore framework
,您可能还需要将它添加到您的项目中,因为您可能会遇到编译器错误。
@Flea 现在,启用模块后,您不应再添加 QuartzCore.framework
。
您可以将43.0f
更改为toScrollView.frame.size.height
以确保它位于底部
使用这样的 CALayer 的大问题是它是固定的。当您的视图大小发生变化(设备旋转、自动布局等)时,您的 CALayer 将不会自动调整自身。你将不得不自己设置它。而使用 drawRect 可以自动处理更改。【参考方案2】:
这是一个更通用的 Swift 扩展,用于为任何 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)
斯威夫特 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)
【讨论】:
您可能希望在每个函数中使用 this 删除先前添加的子层(以防它在循环中被调用) - if let subLayerArray = self.layer.sublayers for layer in subLayerArray layer. removeFromSuperlayer() 提到的宽度是多少? 对于 Swift 3.0 使用border.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: width)
等
@NitinNain 小心,删除的层数比你的意思要多。例如,如果您删除 UIView.layer 的所有层...,当您显示键盘时很可能会看到崩溃
这在 Swift 5 中似乎不起作用。但我也没有看到任何错误,我检查了所有函数和属性是否存在。有什么想法吗?【参考方案3】:
在如下类别中实现:
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];
@end
【讨论】:
干得好.. 但是这段代码有什么特定于 UIButton 的吗?还不如把它添加到 UIView 中没有? 不错的sn-p。我对此进行了重构并转换为 Swift。你可以找到它here。 如果按钮的主层有边框半径怎么办? 我同意@abbood 不妨将其设为UIView 上的一个类别。不过物有所值。 是的,它在 UIView 上工作得很好。相关问题:如何使用自动布局进行这项工作?显然,如果框架发生变化,您需要按原样重新绘制边框。【参考方案4】:斯威夫特 4
如果您需要真正的自适应解决方案(适用于所有屏幕尺寸),那么就是这样:
/**
* Extends UIView with shortcut methods
*
* @author Alexander Volkov
* @version 1.0
*/
extension UIView
/// Adds bottom border to the view with given side margins
///
/// - Parameters:
/// - color: the border color
/// - margins: the left and right margin
/// - borderLineSize: the size of the border
func addBottomBorder(color: UIColor = UIColor.red, margins: CGFloat = 0, borderLineSize: CGFloat = 1)
let border = UIView()
border.backgroundColor = color
border.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(border)
border.addConstraint(NSLayoutConstraint(item: border,
attribute: .height,
relatedBy: .equal,
toItem: nil,
attribute: .height,
multiplier: 1, constant: borderLineSize))
self.addConstraint(NSLayoutConstraint(item: border,
attribute: .bottom,
relatedBy: .equal,
toItem: self,
attribute: .bottom,
multiplier: 1, constant: 0))
self.addConstraint(NSLayoutConstraint(item: border,
attribute: .leading,
relatedBy: .equal,
toItem: self,
attribute: .leading,
multiplier: 1, constant: margins))
self.addConstraint(NSLayoutConstraint(item: border,
attribute: .trailing,
relatedBy: .equal,
toItem: self,
attribute: .trailing,
multiplier: 1, constant: margins))
【讨论】:
@DanielBeltrami 我同意,但我不会强迫审稿人在接受新答案后检查新答案。【参考方案5】:您可以向self.view
添加一个单独的UIView
,高度为1 点,背景颜色为灰色,并将其放置在toScrollView
的正下方。
编辑:除非您有充分的理由(想要使用 CALayer 不提供的 UIView 的某些服务),否则您应该使用 CALayer 作为@MattDiPasquale suggests。 UIView 的开销更大,这在大多数情况下可能不是问题,但其他解决方案仍然更优雅。
【讨论】:
【参考方案6】:Swift 4 的解决方案
let bottomBorder = CALayer()
bottomBorder.frame = CGRect(x: 0.0, y: calendarView.frame.size.height-1, width: calendarView.frame.width, height: 1.0)
bottomBorder.backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
calendarView.layer.addSublayer(bottomBorder)
背景颜色浅灰色。根据需要更改颜色。
【讨论】:
为 CALayer 添加颜色需要将其转换为 CGColor。【参考方案7】:还有带有移除边框功能的改进代码。基于confile answer。
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()
更新: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()
【讨论】:
不错的扩展。清理了一下删除。func remove(border: ViewBorder) layer.sublayers? .compactMap $0 .filter $0.name == border.rawValue .forEach $0.removeFromSuperlayer()
【参考方案8】:
这些扩展方法的问题在于,当 UIView/UIButton 稍后调整它的大小时,您没有机会更改 CALayer 的大小以匹配新的大小。这会给你留下一个错误的边界。我发现子类化我的 UIButton 更好,当然你也可以子类化其他 UIView。 这是一些代码:
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)
【讨论】:
不错的解决方案!谢谢分享。【参考方案9】:或者,最性能友好的方法是重载drawRect,就像这样:
@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
【讨论】:
覆盖drawRect:
不一定对性能友好。我很确定使用层具有更好的性能。
@ThomasW 但是当边界响应设备旋转而改变时会发生什么?还是拆分视图?或者自动布局有什么作用?
@Womble 您需要更新图层以覆盖setFrame:
、setBounds:
或layoutSubviews
方法。
我推荐 layoutSublayersOfLayer:
而不是 setFrame:
或其他任何人【参考方案10】:
如果您使用约束(因此没有框架大小),那么您可以添加具有所需约束的边框视图
// MARK: - Add a border to one side of a view
public enum BorderSide
case top, bottom, left, right
extension UIView
public func addBorder(side: BorderSide, color: UIColor, width: CGFloat)
let border = UIView()
border.translatesAutoresizingMaskIntoConstraints = false
border.backgroundColor = color
self.addSubview(border)
let topConstraint = topAnchor.constraint(equalTo: border.topAnchor)
let rightConstraint = trailingAnchor.constraint(equalTo: border.trailingAnchor)
let bottomConstraint = bottomAnchor.constraint(equalTo: border.bottomAnchor)
let leftConstraint = leadingAnchor.constraint(equalTo: border.leadingAnchor)
let heightConstraint = border.heightAnchor.constraint(equalToConstant: width)
let widthConstraint = border.widthAnchor.constraint(equalToConstant: width)
switch side
case .top:
NSLayoutConstraint.activate([leftConstraint, topConstraint, rightConstraint, heightConstraint])
case .right:
NSLayoutConstraint.activate([topConstraint, rightConstraint, bottomConstraint, widthConstraint])
case .bottom:
NSLayoutConstraint.activate([rightConstraint, bottomConstraint, leftConstraint, heightConstraint])
case .left:
NSLayoutConstraint.activate([bottomConstraint, leftConstraint, topConstraint, widthConstraint])
然后设置如下
myButton.addBorder(side: .left, color: UIColor.lightGray, width: 1)
(灵感来自this answer)
【讨论】:
喜欢这个扩展。谢谢一百万!【参考方案11】:Swift 3 版本的 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)
使用自动布局时的用法:
class CustomView: UIView
override func awakeFromNib()
super.awakeFromNib()
override func layoutSubviews()
addBottomBorderWithColor(color: UIColor.white, width: 1)
【讨论】:
在 iPad 和 iPhone plus 设备上,这条线没有填满整个屏幕。这个@spogebob92 有解决办法吗 猜测是自动布局已经完成,所以在添加边框之前,可能调用 layoutIfNeeded()【参考方案12】:斯威夫特
创建 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)
self.addObserver(self, forKeyPath: #keyPath(UIView.bounds), options: .new, context: UnsafeMutableRawPointer(bitPattern: 1111) )
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)
self.addObserver(self, forKeyPath: #keyPath(UIView.bounds), options: .new, context: UnsafeMutableRawPointer(bitPattern: 2222) )
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)
self.addObserver(self, forKeyPath: #keyPath(UIView.bounds), options: .new, context: UnsafeMutableRawPointer(bitPattern: 3333) )
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)
self.addObserver(self, forKeyPath: #keyPath(UIView.bounds), options: .new, context: UnsafeMutableRawPointer(bitPattern: 4444) )
override open func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?)
if let objectView = object as? UIView,
objectView === self,
keyPath == #keyPath(UIView.bounds)
switch context
case UnsafeMutableRawPointer(bitPattern: 1111):
for border in self.layer.sublayers ?? []
if border.name == "topBorderLayer"
border.frame = CGRect(x: 0, y : 0,width: self.frame.size.width, height: border.frame.height)
case UnsafeMutableRawPointer(bitPattern: 2222):
for border in self.layer.sublayers ?? []
if border.name == "rightBorderLayer"
border.frame = CGRect(x: self.frame.size.width - border.frame.width, y: 0, width : border.frame.width, height :self.frame.size.height)
case UnsafeMutableRawPointer(bitPattern: 3333):
for border in self.layer.sublayers ?? []
if border.name == "bottomBorderLayer"
border.frame = CGRect(x: 0, y: self.frame.size.height - border.frame.height,width : self.frame.size.width,height: border.frame.height)
case UnsafeMutableRawPointer(bitPattern: 4444):
for border in self.layer.sublayers ?? []
if border.name == "leftBorderLayer"
border.frame = CGRect(x:0, y:0,width : border.frame.width, height : self.frame.size.height)
default:
break
func removePreviouslyAddedLayer(name : String)
if self.layer.sublayers?.count ?? 0 > 0
self.layer.sublayers?.forEach
if $0.name == name
$0.removeFromSuperlayer()
目标 C
创建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
static void *topBorderContext = &topBorderContext;
static void *bottomBorderContext = &bottomBorderContext;
static void *leftBorderContext = &leftBorderContext;
static void *rightBorderContext = &rightBorderContext;
static char bottomLineColorKey,topLineColorKey,rightLineColorKey,leftLineColorKey;
@implementation UIView(Utility)
@dynamic borderColor,borderWidth,cornerRadius,bottomLineWidth,topLineWidth,rightLineWidth,leftLineWidth;
-(void)setBorderColor:(UIColor *)borderColor
[self.layer setBorderColor:borderColor.CGColor];
-(void)setBorderWidth:(CGFloat)borderWidth
[self.layer setBorderWidth:borderWidth];
-(void)setCornerRadius:(CGFloat)cornerRadius
[self.layer setCornerRadius:cornerRadius];
// 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
[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
[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
[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
[self addLeftBorderWithColor:[self leftLineColor] andWidth:leftLineWidth];
- (void)addTopBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth
dispatch_async(dispatch_get_main_queue(), ^
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];
[self addObserver:self forKeyPath: @"bounds" options:NSKeyValueObservingOptionNew context:topBorderContext];
);
- (void)addBottomBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth
dispatch_async(dispatch_get_main_queue(), ^
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];
[self addObserver:self forKeyPath: @"bounds" options:NSKeyValueObservingOptionNew context:bottomBorderContext];
);
- (void)addLeftBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth
dispatch_async(dispatch_get_main_queue(), ^
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];
[self addObserver:self forKeyPath: @"bounds" options:NSKeyValueObservingOptionNew context:leftBorderContext];
);
- (void)addRightBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth
dispatch_async(dispatch_get_main_queue(), ^
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];
[self addObserver:self forKeyPath: @"bounds" options:NSKeyValueObservingOptionNew context:rightBorderContext];
);
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
if (context == topBorderContext)
for (CALayer *border in self.layer.sublayers)
if ([border.name isEqualToString:@"topBorderLayer"])
[border setFrame:CGRectMake(0, 0, self.frame.size.width, border.frame.size.height)];
else if (context == bottomBorderContext)
for (CALayer *border in self.layer.sublayers)
if ([border.name isEqualToString:@"bottomBorderLayer"])
[border setFrame:CGRectMake(0, self.frame.size.height - border.frame.size.height, self.frame.size.width, border.frame.size.height)];
else if (context == leftBorderContext)
for (CALayer *border in self.layer.sublayers)
if ([border.name isEqualToString:@"leftBorderLayer"])
[border setFrame:CGRectMake(0, 0, border.frame.size.width, self.frame.size.height)];
else if (context == rightBorderContext)
for (CALayer *border in self.layer.sublayers)
if ([border.name isEqualToString:@"rightBorderLayer"])
[border setFrame:CGRectMake(self.frame.size.width - border.frame.size.width, 0, border.frame.size.width, self.frame.size.height)];
else
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
- (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
用法:- 从情节提要中选择任何控件,然后显示属性检查器(右侧)您将看到下图示例。(注意:边框仅在运行时出现。)
现在您可以设置边框颜色和宽度的任意一侧。
【讨论】:
它的工作.. 谢谢.. 但如果嵌入 UINavigationBar,它计算坐标错误..【参考方案13】:Swift 4
基于:https://***.com/a/32821607/9980800
UIView+边框
extension UIView
enum ViewBorder: String
case left, right, top, bottom
func add(Border border: ViewBorder, withColor color: UIColor = UIColor.lightGray, andWidth width: CGFloat = 1.0)
let borderView = UIView()
borderView.backgroundColor = color
borderView.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(borderView)
NSLayoutConstraint.activate(getConstrainsFor(forView: borderView, WithBorderType: border, andWidth: width))
private func getConstrainsFor(forView borderView: UIView, WithBorderType border: ViewBorder, andWidth width: CGFloat) -> [NSLayoutConstraint]
let height = borderView.heightAnchor.constraint(equalToConstant: width)
let widthAnchor = borderView.widthAnchor.constraint(equalToConstant: width)
let leading = borderView.leadingAnchor.constraint(equalTo: self.leadingAnchor)
let trailing = borderView.trailingAnchor.constraint(equalTo: self.trailingAnchor)
let top = borderView.topAnchor.constraint(equalTo: self.topAnchor)
let bottom = borderView.bottomAnchor.constraint(equalTo: self.bottomAnchor)
switch border
case .bottom:
return [bottom, leading, trailing, height]
case .top:
return [top, leading, trailing, height]
case .left:
return [top, bottom, leading, widthAnchor]
case .right:
return [top, bottom, trailing, widthAnchor]
用法:-
class ViewController: UIViewController
@IBOutlet weak var sampleView: UIView!
override func viewDidLoad()
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
sampleView.add(Border: .bottom)
override func didReceiveMemoryWarning()
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
【讨论】:
【参考方案14】:斯威夫特 4
基于https://***.com/a/32513578/5391914
import UIKit
enum ViewBorder: String
case Left = "borderLeft"
case Right = "borderRight"
case Top = "borderTop"
case Bottom = "borderBottom"
extension UIView
func addBorder(vBorders: [ViewBorder], color: UIColor, width: CGFloat)
vBorders.forEach vBorder in
let border = CALayer()
border.backgroundColor = color.cgColor
border.name = vBorder.rawValue
switch vBorder
case .Left:
border.frame = CGRect(x: 0, y: 0, width: width, height: self.frame.size.height)
case .Right:
border.frame = CGRect(x:self.frame.size.width - width, y: 0, width: width, height: self.frame.size.height)
case .Top:
border.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: width)
case .Bottom:
border.frame = CGRect(x: 0, y: self.frame.size.height - width , width: self.frame.size.width, height: width)
self.layer.addSublayer(border)
【讨论】:
【参考方案15】:我写了一个通用方法,可以在任何UIView
的任意一侧添加边框。您可以为每一边定义厚度、颜色、边距和zOrder
。
/*
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];
【讨论】:
【参考方案16】:您不必为每个边框添加图层,只需使用贝塞尔路径绘制一次即可。
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];
【讨论】:
【参考方案17】:斯威夫特 4/3
您可以在下面使用此解决方案。它适用于比层更轻的 UIBezierPaths,从而导致快速启动时间。它易于使用,请参阅下面的说明。
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()
-
将 UIView 的类设置为 ResizeBorderView
在 viewDidAppear 方法中使用 yourview.color 和 yourview.lineWidth 设置颜色和线宽
设置边缘,例如:yourview.edges = [.right, .left] ([.all]) for all
享受快速启动和调整边框大小
【讨论】:
【参考方案18】:extension UIView
func addBottomLine(color: UIColor, height: CGFloat)
let bottomView = UIView(frame: CGRect(x: 0, y: self.frame.height - 1, width: self.frame.width, height: height))
bottomView.translatesAutoresizingMaskIntoConstraints = false
bottomView.autoresizingMask = .flexibleWidth
bottomView.backgroundColor = color
self.addSubview(bottomView)
【讨论】:
虽然这段代码可以回答这个问题,但最好包含一些上下文,解释它是如何工作的以及何时使用它。从长远来看,纯代码的答案没有用处。 很高兴收到您的来信,我会回答您的问题 -> 1- 首先创建名为您想要的文件,然后从 UIView 创建扩展名,然后添加一个方法,首先是 CGFloat,其次是UIColor 在该方法中添加上面的代码,并将第一行中的 1 更改为高度:CGFloat params 并设置 bottomView.backgroundColor = THE_COLOR_PARAMS【参考方案19】:最完整的答案。 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))
【讨论】:
【参考方案20】:带有边框宽度和颜色的 Swift 4 扩展。 效果很好!
@IBDesignable
final class SideBorders: UIView
@IBInspectable var topColor: UIColor = UIColor.clear
@IBInspectable var topWidth: CGFloat = 0
@IBInspectable var rightColor: UIColor = UIColor.clear
@IBInspectable var rightWidth: CGFloat = 0
@IBInspectable var bottomColor: UIColor = UIColor.clear
@IBInspectable var bottomWidth: CGFloat = 0
@IBInspectable var leftColor: UIColor = UIColor.clear
@IBInspectable var leftWidth: CGFloat = 0
override func draw(_ rect: CGRect)
let topBorder = CALayer()
topBorder.backgroundColor = topColor.cgColor
topBorder.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: topWidth)
self.layer.addSublayer(topBorder)
let rightBorder = CALayer()
rightBorder.backgroundColor = rightColor.cgColor
rightBorder.frame = CGRect(x: self.frame.size.width - rightWidth, y: 0, width: rightWidth, height: self.frame.size.height)
self.layer.addSublayer(rightBorder)
let bottomBorder = CALayer()
bottomBorder.backgroundColor = bottomColor.cgColor
bottomBorder.frame = CGRect(x: 0, y: self.frame.size.height - bottomWidth, width: self.frame.size.width, height: bottomWidth)
self.layer.addSublayer(bottomBorder)
let leftBorder = CALayer()
leftBorder.backgroundColor = leftColor.cgColor
leftBorder.frame = CGRect(x: 0, y: self.frame.size.height - leftWidth, width: self.frame.size.width, height: leftWidth)
self.layer.addSublayer(leftBorder)
【讨论】:
【参考方案21】:斯威夫特 5.1。与两个扩展一起使用,方法返回 CALayer,因此您可以重复使用它来更新帧。
enum Border: Int
case top = 0
case bottom
case right
case left
extension UIView
func addBorder(for side: Border, withColor color: UIColor, borderWidth: CGFloat) -> CALayer
let borderLayer = CALayer()
borderLayer.backgroundColor = color.cgColor
let xOrigin: CGFloat = (side == .right ? frame.width - borderWidth : 0)
let yOrigin: CGFloat = (side == .bottom ? frame.height - borderWidth : 0)
let width: CGFloat = (side == .right || side == .left) ? borderWidth : frame.width
let height: CGFloat = (side == .top || side == .bottom) ? borderWidth : frame.height
borderLayer.frame = CGRect(x: xOrigin, y: yOrigin, width: width, height: height)
layer.addSublayer(borderLayer)
return borderLayer
extension CALayer
func updateBorderLayer(for side: Border, withViewFrame viewFrame: CGRect)
let xOrigin: CGFloat = (side == .right ? viewFrame.width - frame.width : 0)
let yOrigin: CGFloat = (side == .bottom ? viewFrame.height - frame.height : 0)
let width: CGFloat = (side == .right || side == .left) ? frame.width : viewFrame.width
let height: CGFloat = (side == .top || side == .bottom) ? frame.height : viewFrame.height
frame = CGRect(x: xOrigin, y: yOrigin, width: width, height: height)
【讨论】:
如何在addBorder中使用UpdateBorderLayer? 您需要存储一个从 addBorder 方法返回的 CALayer。然后当你需要更新时(例如在 viewDidLayoutSubviews 中)你调用这个方法。否则使用约束【参考方案22】: extension UIView
enum side:String
case top
case bottom
case left
case right
func addBorder(side:side,color:UIColor,width:CGFloat)
let border = CALayer()
border.backgroundColor = color.cgColor
switch side
case .top:
border.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: width)
case .bottom:
border.frame = CGRect(x: 0, y: self.frame.size.height - width, width: self.frame.size.width, height: width)
case .left:
border.frame = CGRect(x: 0, y: 0, width: width, height: self.frame.size.height)
case .right:
border.frame = CGRect(x: self.frame.size.width - width, y: 0, width: width, height: self.frame.size.height)
self.layer.addSublayer(border)
【讨论】:
以上是关于UIView 下边框?的主要内容,如果未能解决你的问题,请参考以下文章