UIView底部边界?

ma1*_*w28 140 border uiview ios

对于UIScrollView *toScrollView(这是屏幕的宽度),我想添加一个灰色的底部边框(与iPhone的原生消息应用程序的撰写视图的to-field完全相同).

为了做到这一点,我跟随Cocoa Touch:如何改变UIView的边框颜色和厚度?并使用自定义覆盖顶部边框UINavigationBar并制作了toScrollViewx坐标-1和宽度322,以便左右边框就在屏幕外.

这看起来很好,但它有点像黑客,我想知道是否有更好的方法来做到这一点.

- (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
}
Run Code Online (Sandbox Code Playgroud)

ma1*_*w28 251

而不是使用UIView@,ImreKelényi建议,您可以使用CALayer:

// Add a bottomBorder.
CALayer *bottomBorder = [CALayer layer];

bottomBorder.frame = CGRectMake(0.0f, 43.0f, toScrollView.frame.size.width, 1.0f);

bottomBorder.backgroundColor = [UIColor colorWithWhite:0.8f 
                                                 alpha:1.0f].CGColor;

[toScrollView.layer addSublayer:bottomBorder];
Run Code Online (Sandbox Code Playgroud)

  • 不要忘记#import <QuartzCore/QuartzCore.h> (25认同)
  • 使用像这样的CALayer的大问题是它是固定的.当视图大小发生变化(设备旋转,自动布局等)时,您的CALayer将不会自动调整.你将不得不自己设置它.而使用drawRect可以自动处理更改. (19认同)
  • 如果你没有它,你可能还需要在项目中添加`QuartzCore framework`,因为你可能会遇到编译器错误. (3认同)
  • 您可以将`43.0f`更改为`toScrollView.frame.size.height`以确保它位于底部 (3认同)
  • @Flea现在,启用模块后,你不应再添加`QuartzCore.framework`了. (2认同)

con*_*ile 73

这是一个更通用的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)
  }
}
Run Code Online (Sandbox Code Playgroud)

斯威夫特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)
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 您可能希望在每个func中使用this删除先前添加的子层(如果在循环中调用它) - 如果让subLayerArray = self.layer.sublayers {for subLayerArray中的层{layer.removeFromSuperlayer()}} (2认同)

Dan*_*rin 60

在以下类别中实施:

的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
Run Code Online (Sandbox Code Playgroud)

的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
Run Code Online (Sandbox Code Playgroud)

  • 干得好......但是有什么关于这个特定于UIButton的代码吗?不妨把它添加到UIView中吗? (7认同)
  • 不错的片段.我重构了这个并转换为Swift.你可以找到它[这里](https://gist.github.com/Isuru-Nanayakkara/496d5713e61125bddcf5). (5认同)

Ale*_*kov 23

斯威夫特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))
    }
}
Run Code Online (Sandbox Code Playgroud)


Imr*_*nyi 18

您可以添加单独UIView的1点高度和灰色背景颜色,self.view并将其放置在右下方toScrollView.

编辑:除非你有充分的理由(想要使用一些不是由CALayer提供的UIView服务),你应该使用CALayer作为@MattDiPasquale建议.UIView有更大的开销,在大多数情况下可能不是问题,但是,另一种解决方案更优雅.


osc*_*lon 12

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)
Run Code Online (Sandbox Code Playgroud)

BackgroundColor lightGray.如果需要,可以改变颜色.


Vla*_*ics 10

还有改进的代码,删除边框功能.基于坦诚的答案.

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

}
Run Code Online (Sandbox Code Playgroud)

更新: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()
        }
    }

}
Run Code Online (Sandbox Code Playgroud)


Sia*_*ter 7

这些扩展方法的问题在于,当UIView/UIButton稍后调整它的大小时,您没有机会更改CALayer的大小以匹配新大小.哪个会让你错位边框.我发现将UIButton子类化更好,你当然也可以将其他UIViews子类化.这是一些代码:

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

}
Run Code Online (Sandbox Code Playgroud)


iag*_*849 6

或者,最性能友好的方式是重载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
Run Code Online (Sandbox Code Playgroud)

  • 覆盖`drawRect:`不一定是性能友好的.我很确定使用图层有更好的性能. (6认同)

Int*_*nti 6

如果您使用约束(因此没有框架大小),那么您可以添加具有所需约束的边框视图

// 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])
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后将其设置为如下所示

myButton.addBorder(side: .left, color: UIColor.lightGray, width: 1)
Run Code Online (Sandbox Code Playgroud)

(受到这个答案的启发)


spo*_*b92 5

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

使用自动布局时的用法:

class CustomView: UIView {

    override func awakeFromNib() {
        super.awakeFromNib()
    }

    override func layoutSubviews() {
        addBottomBorderWithColor(color: UIColor.white, width: 1)
    }
}
Run Code Online (Sandbox Code Playgroud)


Dat*_*tel 5

迅速

创建 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()
            }
        }
    }
   }
}
Run Code Online (Sandbox Code Playgroud)

目标 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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

用法:- 从情节提要中选择任何控件,然后显示属性检查器(右侧)您将看到下图示例。(注意:边框仅在运行时出现。)

现在您可以设置边框颜色和宽度的任何一侧。