UIView底边框?


145

UIScrollView *toScrollView我要添加一个(这是屏幕的宽度)的灰色底边框(与iPhone的本地Messages应用程序的compose视图的to-field的边框完全一样)。

为此,我遵循了可可触摸:如何更改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
}

这是一个方便的UIView类别,使您可以在UIView的任何一侧创建基于图层或基于视图的边框:UIView + Borders
aroooo 2013年

Answers:


257

代替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];

25
不要忘记#import <QuartzCore / QuartzCore.h>
凯尔·克莱格

3
QuartzCore framework如果您没有项目,还可能需要将其添加到项目中,因为这样可能会导致编译器错误。
跳蚤

2
@Flea现在,启用模块后,您就不再需要添加QuartzCore.framework了。
ma11hew28 2013年

3
您可以更改43.0ftoScrollView.frame.size.height确保它位于底部
mparryy 2015年

19
像这样使用CALayer的BIG问题是它已修复。当视图的大小发生变化(设备旋转,自动布局等)时,CALayer不会自动调整自身。您将必须自己进行设置。而使用drawRect可以自动处理更改。
2015年

78

这是更通用的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)
    }
}

2
您可能希望在每个函数中使用此功能删除先前添加的子图层(以防在循环中调用)-如果让subLayerArray = self.layer.sublayers {用于subLayerArray中的图层{layer.removeFromSuperlayer()}}
Nitin Nain

1
提到的宽度是多少?
G.Abhisek '16

对于夫特3.0使用border.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: width)
lenooh

@NitinNain小心,它会去除比您想要的更多的层。例如,如果删除UIView.layer的所有层,则在显示键盘时很有可能会崩溃。–
xaphod

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

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

7
很好..但是有关此代码的特定于UIButton的内容吗?最好将其添加到UIView中吗?
2014年

5
不错的摘要。我将其重构并转换为Swift。你可以在这里找到它。
Isuru 2015年

如果按钮的主层具有边框半径怎么办?

我同意@abbood也可以将其设为UIView上的类别。物有所值。
罗伯特·克莱格

是的,它可以在UIView上正常工作。相关问题:如何使它与自动版式一起工作?显然,如果框架发生变化,则需要照原样重新绘制边框。
elsurudo

26

斯威夫特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我同意,但是在接受一个答案后,我不怎么强迫审阅者检查新答案。
亚历山大·沃尔科夫

19

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

编辑:除非您有充分的理由(想使用CALayer不提供的UIView的某些服务),否则应使用@MattDiPasquale建议的 CALayer 。UIView具有更大的开销,这在大多数情况下可能不是问题,但是,其他解决方案却更优雅。


13

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)

背景颜色浅灰色。根据需要更改颜色。


11

还改进了具有删除边框功能的代码。基于confile的答案

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() } }
马修·科普oraal

7

这些扩展方法的问题在于,当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)
    }

}

不错的解决方案!感谢你的分享。
托马斯·卡尔蒙

7

或者,最性能友好的方法是重载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

6
覆盖drawRect:不一定对性能友好。我很确定使用图层具有更好的性能。
ThomasW

1
@ThomasW但是,当边界随着设备旋转而变化时会发生什么?还是分割视图?还是自动版式有什么用?
2015年

@Womble您需要在任的倍率时更新层setFrame:setBounds:layoutSubviews方法。
ThomasW

我会推荐layoutSublayersOfLayer:而不是setFrame:或其他任何人
科恩。

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

使用自动布局时的用法:

class CustomView: UIView {

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

    override func layoutSubviews() {
        addBottomBorderWithColor(color: UIColor.white, width: 1)
    }
}

在iPad和iPhone plus设备上,这条线无法填满整个屏幕。@ spogebob92
Grumme '17

猜猜将是自动布局已经完成,所以在添加边框之前,可能会调用layoutIfNeeded()
spogebob92

5

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

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

(受此答案启发)


爱扩展。谢谢你!
菲利普·雅各布斯

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

目标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的,它的计算坐标错误..
delavega66

2

我写了一个通用的方法,可以在任何一个你希望的两侧都加边框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];
    }
}

2

您不必为每个边框添加一个图层,只需使用贝塞尔曲线路径绘制一次即可。

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];

2

迅捷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])
  4. 享受快速入门和调整边框大小

2

斯威夫特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.
}
}

2

斯威夫特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)
        }
    }
}

1

最完整的答案。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))

在此处输入图片说明


1

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

}


1

雨燕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?
Chandan Jee

您需要存储从addBorder方法返回的CALayer。然后,当您需要更新时(例如在viewDidLayoutSubviews中),请调用此方法。否则使用约束
伊万·特卡琴科

1

扩展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)

}

}


尽管此代码可以回答问题,但最好包含一些上下文,解释其工作方式和使用时间。从长远来看,纯代码答案没有用。
Mustafa

我很高兴收到您的来信,我将回答您的问题-> 1-首先创建一个名为您想要的文件,然后从UIView创建扩展名,然后添加一个方法,首先是CGFloat,然后是UIColor在该方法中添加上面的代码并在第一行中将高度更改为1:CGFloat参数并设置bottomView.backgroundColor = {THE_COLOR_PARAMS}
艾哈迈德·萨米尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.