【问题标题】:UIView bottom border?UIView 下边框?
【发布时间】: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

标签: ios uiview border


【解决方案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];

【讨论】:

  • 别忘了#import
  • 如果您没有 QuartzCore 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://stackoverflow.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://stackoverflow.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()
                    }
                }
            }
            
            1. 将 UIView 的类设置为 ResizeBorderView
            2. 在 viewDidAppear 方法中使用 yourview.color 和 yourview.lineWidth 设置颜色和线宽
            3. 设置边缘,例如:yourview.edges = [.right, .left] ([.all]) for all
            4. 享受快速启动和调整边框大小

            【讨论】:

              【解决方案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)
                  }
                  

                  }

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2015-04-27
                    • 1970-01-01
                    • 1970-01-01
                    • 2012-06-29
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多