it-roy-ru.com

Как добавить границу только на верхней стороне UIView

У меня вопрос по названию.

Я не знаю, как добавить границу с определенной стороны, сверху или снизу, с любой стороны ...layer.border рисует границу для всего вида ...

120
manonthemoon

Я считаю, что подклассы UIView и переопределение drawRect излишни здесь. Почему бы не добавить расширение в UIView и добавить границы подпредставлений?

@discardableResult
func addBorders(edges: UIRectEdge,
                color: UIColor,
                inset: CGFloat = 0.0,
                thickness: CGFloat = 1.0) -> [UIView] {

    var borders = [UIView]()

    @discardableResult
    func addBorder(formats: String...) -> UIView {
        let border = UIView(frame: .zero)
        border.backgroundColor = color
        border.translatesAutoresizingMaskIntoConstraints = false
        addSubview(border)
        addConstraints(formats.flatMap {
            NSLayoutConstraint.constraints(withVisualFormat: $0,
                                           options: [],
                                           metrics: ["inset": inset, "thickness": thickness],
                                           views: ["border": border]) })
        borders.append(border)
        return border
    }


    if edges.contains(.top) || edges.contains(.all) {
        addBorder(formats: "V:|-0-[border(==thickness)]", "H:|-inset-[border]-inset-|")
    }

    if edges.contains(.bottom) || edges.contains(.all) {
        addBorder(formats: "V:[border(==thickness)]-0-|", "H:|-inset-[border]-inset-|")
    }

    if edges.contains(.left) || edges.contains(.all) {
        addBorder(formats: "V:|-inset-[border]-inset-|", "H:|-0-[border(==thickness)]")
    }

    if edges.contains(.right) || edges.contains(.all) {
        addBorder(formats: "V:|-inset-[border]-inset-|", "H:[border(==thickness)]-0-|")
    }

    return borders
}

    // Usage:         
    view.addBorder(edges: [.all]) // All with default arguments 
    view.addBorder(edges: [.top], color: .green) // Just Top, green, default thickness
    view.addBorder(edges: [.left, .right, .bottom], color: .red, thickness: 3) // All except Top, red, thickness 3

С этим кодом вы тоже не привязаны к своему подклассу, вы можете применить его ко всему и всем, что наследует от UIView - многоразового использования в вашем проекте и любых других. Передайте другие аргументы вашим методам, чтобы определить другие цвета и ширины. Много вариантов.

185
Adam Waite

Swift версия удивительное дополнение Адама Уэйта 5/5/15 :

extension CALayer {

  func addBorder(Edge: UIRectEdge, color: UIColor, thickness: CGFloat) {

    var border = CALayer()

    switch Edge {
    case .Top:
        border.frame = CGRectMake(0, 0, CGRectGetWidth(self.frame), thickness)
        break
    case .Bottom:
        border.frame = CGRectMake(0, CGRectGetHeight(self.frame) - thickness, CGRectGetWidth(self.frame), thickness)
        break
    case .Left:
        border.frame = CGRectMake(0, 0, thickness, CGRectGetHeight(self.frame))
        break
    case .Right:
        border.frame = CGRectMake(CGRectGetWidth(self.frame) - thickness, 0, thickness, CGRectGetHeight(self.frame))
        break
    default:
        break
    }

    border.backgroundColor = color.CGColor;

    addSublayer(border)
  }
}

Свифт 3:

extension CALayer {

    func addBorder(Edge: UIRectEdge, color: UIColor, thickness: CGFloat) {

        let border = CALayer()

        switch Edge {
        case .top:
            border.frame = CGRect(x: 0, y: 0, width: frame.width, height: thickness)
        case .bottom:
            border.frame = CGRect(x: 0, y: frame.height - thickness, width: frame.width, height: thickness)
        case .left:
            border.frame = CGRect(x: 0, y: 0, width: thickness, height: frame.height)
        case .right:
            border.frame = CGRect(x: frame.width - thickness, y: 0, width: thickness, height: frame.height)
        default:
            break
        }

        border.backgroundColor = color.cgColor;

        addSublayer(border)
    }
}
83
Dan

Лучший способ для меня - это категория в UIView, но добавление представлений вместо CALayers, чтобы мы могли воспользоваться AutoresizingMasks, чтобы убедиться, что границы изменяются вместе с суперпредставлением.

- (void)addTopBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth {
    UIView *border = [UIView new];
    border.backgroundColor = color;
    [border setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin];
    border.frame = CGRectMake(0, 0, self.frame.size.width, borderWidth);
    [self addSubview:border];
}

- (void)addBottomBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth {
    UIView *border = [UIView new];
    border.backgroundColor = color;
    [border setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin];
    border.frame = CGRectMake(0, self.frame.size.height - borderWidth, self.frame.size.width, borderWidth);
    [self addSubview:border];
}

- (void)addLeftBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth {
    UIView *border = [UIView new];
    border.backgroundColor = color;
    border.frame = CGRectMake(0, 0, borderWidth, self.frame.size.height);
    [border setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleRightMargin];
    [self addSubview:border];
}

- (void)addRightBorderWithColor:(UIColor *)color andWidth:(CGFloat) borderWidth {
    UIView *border = [UIView new];
    border.backgroundColor = color;
    [border setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin];
    border.frame = CGRectMake(self.frame.size.width - borderWidth, 0, borderWidth, self.frame.size.height);
    [self addSubview:border];
}
40
Pauls

Swift 3.0

Swift 4.1

extension CALayer {

    func addBorder(Edge: UIRectEdge, color: UIColor, thickness: CGFloat) {

        let border = CALayer();

        switch Edge {
        case UIRectEdge.top:
            border.frame = CGRect(x: 0, y: 0, width: self.frame.width, height: thickness)
            break
        case UIRectEdge.bottom:
            border.frame = CGRect(x:0, y:self.frame.height - thickness, width:self.frame.width, height:thickness)
            break
        case UIRectEdge.left:
            border.frame = CGRect(x:0, y:0, width: thickness, height: self.frame.height)
            break
        case UIRectEdge.right:
            border.frame = CGRect(x:self.frame.width - thickness, y: 0, width: thickness, height:self.frame.height)
            break
        default:
            break
        }

        border.backgroundColor = color.cgColor;

        self.addSublayer(border)
    }

}
23
AleyRobotics

Подкласс UIView и реализовать drawRect: в вашем подклассе, например:

Objective-c

- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextMoveToPoint(context, CGRectGetMinX(rect), CGRectGetMinY(rect));
    CGContextAddLineToPoint(context, CGRectGetMaxX(rect), CGRectGetMinY(rect));
    CGContextSetStrokeColorWithColor(context, [[UIColor redColor] CGColor] );
    CGContextSetLineWidth(context, 2.0);
    CGContextStrokePath(context);
}

Swift 4

override func draw(_ rect: CGRect) {

    let cgContext = UIGraphicsGetCurrentContext()
    cgContext?.move(to: CGPoint(x: rect.minX, y: rect.minY))
    cgContext?.addLine(to: CGPoint(x: rect.maxX, y: rect.minY))
    cgContext?.setStrokeColor(UIColor.red.cgColor)
    cgContext?.setLineWidth(2.0)
    cgContext?.strokePath()
}

Это рисует 2-пиксельную красную линию в качестве верхней границы. Все остальные упомянутые вами варианты оставлены для читателя как тривиальное упражнение.

Кварц 2D Руководство по программированию рекомендуется.

21
FluffulousChimp

Код для выбранного ответа, на случай, если кто-то захочет.

ПРИМЕЧАНИЕ. Это не работает с автоматическим размещением (иначе говоря, вращением устройства в альбомной ориентации и т.д.). 

Сначала определите толщину:

NSInteger borderThickness = 1;

Затем просто скопируйте, используйте любой или все из них, чтобы установить границу, которую вы хотите установить.

Верхняя граница

UIView *topBorder = [UIView new];
topBorder.backgroundColor = [UIColor lightGrayColor];
topBorder.frame = CGRectMake(0, 0, myView.frame.size.width, borderThickness);
[myView addSubview:topBorder];

Нижняя граница

UIView *bottomBorder = [UIView new];
bottomBorder.backgroundColor = [UIColor lightGrayColor];
bottomBorder.frame = CGRectMake(0, myView.frame.size.height - borderThickness, myView.frame.size.width, borderThickness);
[myView addSubview:bottomBorder];

Левая граница

UIView *leftBorder = [UIView new];
leftBorder.backgroundColor = [UIColor lightGrayColor];
leftBorder.frame = CGRectMake(0, 0, borderThickness, myView.frame.size.height);
[myView addSubview:leftBorder];

Правая граница

UIView *rightBorder = [UIView new];
rightBorder.backgroundColor = [UIColor lightGrayColor];
rightBorder.frame = CGRectMake(myView.frame.size.width - borderThickness, 0, borderThickness, myView.frame.size.height);
[myView addSubview:rightBorder];
19
Travis M.

Swift версия:

var myView = UIView(frame: CGRect(x: 100, y: 100, width: 100, height: 100))
myView.backgroundColor = UIColor.yellowColor() 

var border = CALayer()
border.backgroundColor = UIColor.lightGrayColor()
border.frame = CGRect(x: 0, y: 0, width: myView.frame.width, height: 0.5)

myView.layer.addSublayer(border)

Правка: Для получения обновленных версий проверьте мое репо здесь: https://github.com/goktugyil/EZSwiftExtensions/blob/master/Sources/UIViewExtensions.Swift

Посмотрите на части addBorder

13
Esqarrouth

Старый вопрос, но autolayout-решение с настройками границ времени выполнения все еще отсутствует.

borders(for: [.left, .bottom], width: 2, color: .red)

Следующее расширение UIView добавит границу только по заданным ребрам. Если вы измените края во время выполнения, границы будут скорректированы соответствующим образом.

extension UIView {
    func borders(for edges:[UIRectEdge], width:CGFloat = 1, color: UIColor = .black) {

        if edges.contains(.all) {
            layer.borderWidth = width
            layer.borderColor = color.cgColor
        } else {
            let allSpecificBorders:[UIRectEdge] = [.top, .bottom, .left, .right]

            for Edge in allSpecificBorders {
                if let v = viewWithTag(Int(Edge.rawValue)) {
                    v.removeFromSuperview()
                }

                if edges.contains(Edge) {
                    let v = UIView()
                    v.tag = Int(Edge.rawValue)
                    v.backgroundColor = color
                    v.translatesAutoresizingMaskIntoConstraints = false
                    addSubview(v)

                    var horizontalVisualFormat = "H:"
                    var verticalVisualFormat = "V:"

                    switch Edge {
                    case UIRectEdge.bottom:
                        horizontalVisualFormat += "|-(0)-[v]-(0)-|"
                        verticalVisualFormat += "[v(\(width))]-(0)-|"
                    case UIRectEdge.top:
                        horizontalVisualFormat += "|-(0)-[v]-(0)-|"
                        verticalVisualFormat += "|-(0)-[v(\(width))]"
                    case UIRectEdge.left:
                        horizontalVisualFormat += "|-(0)-[v(\(width))]"
                        verticalVisualFormat += "|-(0)-[v]-(0)-|"
                    case UIRectEdge.right:
                        horizontalVisualFormat += "[v(\(width))]-(0)-|"
                        verticalVisualFormat += "|-(0)-[v]-(0)-|"
                    default:
                        break
                    }

                    self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: horizontalVisualFormat, options: .directionLeadingToTrailing, metrics: nil, views: ["v": v]))
                    self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: verticalVisualFormat, options: .directionLeadingToTrailing, metrics: nil, views: ["v": v]))
                }
            }
        }
    }
}
10
seeppp

// MARK: - Добавить LeftBorder для просмотра

(void)prefix_addLeftBorder:(UIView *) viewName
{
    CALayer *leftBorder = [CALayer layer];
    leftBorder.backgroundColor = [UIColor colorWithRed:221/255.0f green:221/255.0f blue:221/255.0f alpha:1.0f].CGColor;
    leftBorder.frame = CGRectMake(0,0,1.0,viewName.frame.size.height);
    [viewName.layer addSublayer:leftBorder];
}

// MARK: - Добавить RightBorder для просмотра

(void)prefix_addRightBorder:(UIView *) viewName
{
    CALayer *rightBorder = [CALayer layer];
    rightBorder.backgroundColor = [UIColor colorWithRed:221/255.0f green:221/255.0f blue:221/255.0f alpha:1.0f].CGColor;
    rightBorder.frame = CGRectMake(viewName.frame.size.width - 1.0,0,1.0,viewName.frame.size.height);
    [viewName.layer addSublayer:rightBorder];
}

// MARK: - Добавить нижнюю границу для просмотра

(void)prefix_addbottomBorder:(UIView *) viewName
{
    CALayer *bottomBorder = [CALayer layer];
    bottomBorder.backgroundColor = [UIColor colorWithRed:221/255.0f green:221/255.0f blue:221/255.0f alpha:1.0f].CGColor;
    bottomBorder.frame = CGRectMake(0,viewName.frame.size.height - 1.0,viewName.frame.size.width,1.0);
    [viewName.layer addSublayer:bottomBorder];
}
4
Priyanka Jadhav

Я взял ответы Адама Уэйта и Полса и соединил их. Я также добавил возможность соединить выбранные ребра вместе, поэтому вам нужно вызвать только одну функцию, например:

[self.view addBordersToEdge:(UIRectEdgeLeft|UIRectEdgeRight)
                  withColor:[UIColor grayColor]
                   andWidth:1.0];

или так:

[self.view addBordersToEdge:(UIRectEdgeAll)
                  withColor:[UIColor grayColor]
                   andWidth:1.0];

Вам нужно реализовать категорию на UIView, как это предлагается в других ответах со следующей реализацией:

- (void)addBordersToEdge:(UIRectEdge)Edge withColor:(UIColor *)color andWidth:(CGFloat) borderWidth {
    if (Edge & UIRectEdgeTop) {
        UIView *border = [UIView new];
        border.backgroundColor = color;
        [border setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin];
        border.frame = CGRectMake(0, 0, self.frame.size.width, borderWidth);
        [self addSubview:border];
    }

    if (Edge & UIRectEdgeLeft) {
        UIView *border = [UIView new];
        border.backgroundColor = color;
        border.frame = CGRectMake(0, 0, borderWidth, self.frame.size.height);
        [border setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleRightMargin];
        [self addSubview:border];
    }

    if (Edge & UIRectEdgeBottom) {
        UIView *border = [UIView new];
        border.backgroundColor = color;
        [border setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin];
        border.frame = CGRectMake(0, self.frame.size.height - borderWidth, self.frame.size.width, borderWidth);
        [self addSubview:border];
    }

    if (Edge & UIRectEdgeRight) {
        UIView *border = [UIView new];
        border.backgroundColor = color;
        [border setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin];
        border.frame = CGRectMake(self.frame.size.width - borderWidth, 0, borderWidth, self.frame.size.height);
        [self addSubview:border];
    }
}
4
Maco03

Вот простое решение. Добавьте ярлык на UIView, очистите текст на ярлыке и установите цвет фона ярлыка в качестве цвета рамки. Установите (x,y) Происхождения вашего ярлыка как (x,y) Происхождения вашего представления. и установите ширину метки равной ширине вашей UIView, установите высоту равной 1 или 2 (для высоты границы в верхней части вашей UIView). И это должно сработать.

3
If Pollavith

Я внес некоторые изменения в ответ Дэна чтобы я мог добавить границы для нескольких ребер одной командой:

infoView.addBorder(toEdges: [.left, .bottom, .right], color: borderColor, thickness: 1)

Вот полный код:

extension UIView {
    func addBorder(toEdges edges: UIRectEdge, color: UIColor, thickness: CGFloat) {

        func addBorder(toEdge edges: UIRectEdge, color: UIColor, thickness: CGFloat) {
            let border = CALayer()
            border.backgroundColor = color.cgColor

            switch edges {
            case .top:
                border.frame = CGRect(x: 0, y: 0, width: frame.width, height: thickness)
            case .bottom:
                border.frame = CGRect(x: 0, y: frame.height - thickness, width: frame.width, height: thickness)
            case .left:
                border.frame = CGRect(x: 0, y: 0, width: thickness, height: frame.height)
            case .right:
                border.frame = CGRect(x: frame.width - thickness, y: 0, width: thickness, height: frame.height)
            default:
                break
            }

            layer.addSublayer(border)
        }

        if edges.contains(.top) || edges.contains(.all) {
            addBorder(toEdge: .top, color: color, thickness: thickness)
        }

        if edges.contains(.bottom) || edges.contains(.all) {
            addBorder(toEdge: .bottom, color: color, thickness: thickness)
        }

        if edges.contains(.left) || edges.contains(.all) {
            addBorder(toEdge: .left, color: color, thickness: thickness)
        }

        if edges.contains(.right) || edges.contains(.all) {
            addBorder(toEdge: .right, color: color, thickness: thickness)
        }
    }
}
3
NSExceptional

Swift 4.2 и AutoLayout

Я прошел предложенные решения. Многие основаны на фреймах. Это простое расширение, которое работает с AutoLayout - используйте View вместо Layer, чтобы убедиться, что мы можем использовать AutoLayout - Single subview с 4 ограничениями.

Используйте следующим образом:

self.addBorder(.bottom, color: .lightGray, thickness: 0.5)


extension UIView {
    func addBorder(_ Edge: UIRectEdge, color: UIColor, thickness: CGFloat) {
        let subview = UIView()
        subview.translatesAutoresizingMaskIntoConstraints = false
        subview.backgroundColor = color
        self.addSubview(subview)
        switch Edge {
        case .top, .bottom:
            subview.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 0).isActive = true
            subview.rightAnchor.constraint(equalTo: self.rightAnchor, constant: 0).isActive = true
            subview.heightAnchor.constraint(equalToConstant: thickness).isActive = true
            if Edge == .top {
                subview.topAnchor.constraint(equalTo: self.topAnchor, constant: 0).isActive = true
            } else {
                subview.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 0).isActive = true
            }
        case .left, .right:
            subview.topAnchor.constraint(equalTo: self.topAnchor, constant: 0).isActive = true
            subview.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 0).isActive = true
            subview.widthAnchor.constraint(equalToConstant: thickness).isActive = true
            if Edge == .left {
                subview.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 0).isActive = true
            } else {
                subview.rightAnchor.constraint(equalTo: self.rightAnchor, constant: 0).isActive = true
            }
        default:
            break
        }
    }
}
2
eharo2

Мой ответ на аналогичный вопрос: https://stackoverflow.com/a/27141956/435766 Я лично предпочитаю идти по дороге категории на этом, так как я хочу иметь возможность использовать его на любом подкласс UIView.

2
P. Unto

Основываясь на ответе NSBum , я применил аналогичный подход и создал этот простой подкласс UIView, чтобы он работал в Интерфейсном Разработчике и работал с ограничениями: ссылка на github
Используя CGContextFillRect вместо CGContextStrokePath, я смог предсказуемо сохранить линии полностью сплошными и в границах представления.

Вот мой пост в блоге об этом: http://natrosoft.com/?p=55

- В основном просто поместите UIView в Интерфейсный Разработчик и измените его тип класса на NAUIViewWithBorders.
-- Затем в viewDidLoad вашего VC сделать что-то вроде: 

/* For a top border only ———————————————- */
self.myBorderView.borderColorTop = [UIColor redColor];
self.myBorderView..borderWidthsAll = 1.0f;

/* For borders with different colors and widths ————————— */
self.myBorderView.borderWidths = UIEdgeInsetsMake(2.0, 4.0, 6.0, 8.0);
self.myBorderView.borderColorTop = [UIColor blueColor];
self.myBorderView.borderColorRight = [UIColor redColor];
self.myBorderView.borderColorBottom = [UIColor greenColor];
self.myBorderView.borderColorLeft = [UIColor darkGrayColor];

Вот прямая ссылка на файл .m , чтобы вы могли увидеть реализацию . Также есть демонстрационный проект. Надеюсь, это поможет кому-то :)

2
n8tr

Просто публикуем здесь, чтобы помочь кому-то, ищущему добавить границы. Я внес несколько изменений в принятый ответ здесь Swift label only only border left . Изменена ширина в случае UIRectEdge.Top с CGRectGetHeight(self.frame) на CGRectGetWidth(self.frame) и в случае UIRectEdge.Bottom с UIScreen.mainScreen().bounds.width на CGRectGetWidth(self.frame) для правильного получения границ. Использование Swift 2.

Наконец, расширение: 

extension CALayer {

func addBorder(Edge: UIRectEdge, color: UIColor, thickness: CGFloat) {

    let border = CALayer();

    switch Edge {
    case UIRectEdge.Top:
        border.frame = CGRectMake(0, 0, CGRectGetWidth(self.frame), thickness); 
        break
    case UIRectEdge.Bottom:
        border.frame = CGRectMake(0, CGRectGetHeight(self.frame) - thickness, CGRectGetWidth(self.frame), thickness)
        break
    case UIRectEdge.Left:
        border.frame = CGRectMake(0, 0, thickness, CGRectGetHeight(self.frame))
        break
    case UIRectEdge.Right:
        border.frame = CGRectMake(CGRectGetWidth(self.frame) - thickness, 0, thickness, CGRectGetHeight(self.frame))
        break
    default:
        break
    }

    border.backgroundColor = color.CGColor;

    self.addSublayer(border)
}

}
1
Kavisha_31

Я придумал решение, использующее Swift 4.1, которое использует AutoLayout и UIViews, чтобы оно изменило размеры с представлением.

Он основан на ответе @AdamWaite, но решает проблему для ячеек табличного представления, где ячейки используются повторно. Если предыдущая граница не была удалена до добавления новой, то повторно используемая ячейка будет содержать несколько границ.

Это решается созданием фиктивного класса BorderView, поиском в подпредставлении границ и их удалением.

Этот код использует SnapKit для ограничений и CocoaLumberjack для отладки. Если вы их не используете, то конвертировать должно быть довольно просто

class BorderView: UIView {
}

extension UIView {
    private func addSidedBorder(toEdge Edge: UIRectEdge, withColor color: UIColor, inset: CGFloat, thickness: CGFloat) {
        let border = BorderView(frame: .zero)
        border.backgroundColor = color
        addSubview(border)

        border.snp.makeConstraints { make in
            switch Edge {
            case .top:
                make.top.equalToSuperview()
                make.height.equalTo(thickness)
                make.left.right.equalToSuperview().inset(inset)

            case .left:
                make.left.equalToSuperview()
                make.width.equalTo(thickness)
                make.top.bottom.equalToSuperview().inset(inset)

            case .bottom:
                make.bottom.equalToSuperview()
                make.height.equalTo(thickness)
                make.left.right.equalToSuperview().inset(inset)

            case .right:
                make.right.equalToSuperview()
                make.width.equalTo(thickness)
                make.top.bottom.equalToSuperview().inset(inset)

            default:
                DDLogWarn("Invalid sided border given in ExtendedUIView, border not added correctly")
            }
        }
    }

    func addBorder(toEdge Edge: UIRectEdge, withColor color: UIColor = .black, inset: CGFloat = 0.0, thickness: CGFloat = 1.0) {
        // Remove existing borders from view and readd them
        for view in subviews {
            if view is BorderView {
                view.removeFromSuperview()
            }
        }

        if Edge.contains(.all) {
            addSidedBorder(toEdge: .top, withColor: color, inset: inset, thickness: thickness)
            addSidedBorder(toEdge: .left, withColor: color, inset: inset, thickness: thickness)
            addSidedBorder(toEdge: .bottom, withColor: color, inset: inset, thickness: thickness)
            addSidedBorder(toEdge: .right, withColor: color, inset: inset, thickness: thickness)
        } else {
            if Edge.contains(.top) {
                addSidedBorder(toEdge: .top, withColor: color, inset: inset, thickness: thickness)
            }

            if Edge.contains(.left) {
                addSidedBorder(toEdge: .left, withColor: color, inset: inset, thickness: thickness)
            }

            if Edge.contains(.bottom) {
                addSidedBorder(toEdge: .bottom, withColor: color, inset: inset, thickness: thickness)
            }

            if Edge.contains(.right) {
                addSidedBorder(toEdge: .right, withColor: color, inset: inset, thickness: thickness)
            }
        }
    }
}

Добавьте этот код и затем в классе, который подклассы UIView, вызовите:

view.addBorder(toEdge: [.left, .right], withColor: .red, inset: 0.0, thickness: 1.0)
1
Addison

Если я строю из раскадровки, я предпочитаю добавить UIView позади моей полезной UIView... Если я хочу создать границу на вершине моей UIView, я просто увеличиваю высоту фона UIView на ширину моей границы. То же самое можно сделать для любой другой стороны :)

1
Adrián Rivero

Версия Swift 3

extension UIView {
    enum ViewSide {
        case Top, Bottom, Left, Right
    }

    func addBorder(toSide side: ViewSide, withColor color: UIColor, andThickness thickness: CGFloat) {

        let border = CALayer()
        border.backgroundColor = color.cgColor

        switch side {
        case .Top:
            border.frame = CGRect(x: 0, y: 0, width: frame.size.width, height: thickness)
        case .Bottom:
            border.frame = CGRect(x: 0, y: frame.size.height - thickness, width: frame.size.width, height: thickness)
        case .Left:
            border.frame = CGRect(x: 0, y: 0, width: thickness, height: frame.size.height)
        case .Right:
            border.frame = CGRect(x: frame.size.width - thickness, y: 0, width: thickness, height: frame.size.height)
        }

        layer.addSublayer(border)
    }
}

Чтобы установить соответствующую границу, вы должны переопределить viewDidLayoutSubviews () метод:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    yourView.addBorder(toSide: UIView.ViewSide.Top, withColor: UIColor.lightGray, andThickness: 1)
1
karjaubayev

Вот версия Swift 4 ответ Паулса

func addTopBorder(color: UIColor, thickness: CGFloat) {
    let border = UIView()
    border.backgroundColor = color
    border.autoresizingMask = [.flexibleWidth, .flexibleBottomMargin]
    border.frame = CGRect(x: 0, y: 0, width: frame.size.width, height: thickness)
    addSubview(border)
}

func addBottomBorder(color: UIColor, thickness: CGFloat) {
    let border = UIView()
    border.backgroundColor = color
    border.autoresizingMask = [.flexibleWidth, .flexibleTopMargin]
    border.frame = CGRect(x: 0, y: frame.size.height - thickness, width: frame.size.width, height: thickness)
    addSubview(border)
}

func addLeftBorder(color: UIColor, thickness: CGFloat) {
    let border = UIView()
    border.backgroundColor = color
    border.autoresizingMask = [.flexibleHeight, .flexibleRightMargin]
    border.frame = CGRect(x: 0, y: 0, width: thickness, height: frame.size.height)
    addSubview(border)
}

func addRightBorder(color: UIColor, thickness: CGFloat) {
    let border = UIView()
    border.backgroundColor = color
    border.autoresizingMask = [.flexibleHeight, .flexibleLeftMargin]
    border.frame = CGRect(x: frame.size.width - thickness, y: 0, width: thickness, height: frame.size.height)
    addSubview(border)
}
1
NSExceptional
extension UIView {

    func addBorder(Edge: UIRectEdge, color: UIColor, borderWidth: CGFloat) {

        let seperator = UIView()
        self.addSubview(seperator)
        seperator.translatesAutoresizingMaskIntoConstraints = false

        seperator.backgroundColor = color

        if Edge == .top || Edge == .bottom
        {
            seperator.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 0).isActive = true
            seperator.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: 0).isActive = true
            seperator.heightAnchor.constraint(equalToConstant: borderWidth).isActive = true

            if Edge == .top
            {
                seperator.topAnchor.constraint(equalTo: self.topAnchor, constant: 0).isActive = true
            }
            else
            {
                seperator.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 0).isActive = true
            }
        }
        else if Edge == .left || Edge == .right
        {
            seperator.topAnchor.constraint(equalTo: self.topAnchor, constant: 0).isActive = true
            seperator.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 0).isActive = true
            seperator.widthAnchor.constraint(equalToConstant: borderWidth).isActive = true

            if Edge == .left
            {
                seperator.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 0).isActive = true
            }
            else
            {
                seperator.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: 0).isActive = true
            }
        }
    }

}
1
Ali Seymen

Вдохновленный @Addison, я переписал расширение без использования сторонних фреймворков, так как он использовал SnapKit и CocoaLumberjack.

Как и в подходе @Addisons, я также удаляю ранее добавленные границы, поэтому эта реализация должна воспроизводить Nice с многократно используемыми представлениями в качестве ячеек таблицы и ячеек коллекции.

fileprivate class BorderView: UIView {} // dummy class to help us differentiate among border views and other views
                                        // to enabling us to remove existing borders and place new ones

extension UIView {

    func setBorders(toEdges edges: [UIRectEdge], withColor color: UIColor, inset: CGFloat = 0, thickness: CGFloat) {
        // Remove existing edges
        for view in subviews {
            if view is BorderView {
                view.removeFromSuperview()
            }
        }
        // Add new edges
        if edges.contains(.all) {
            addSidedBorder(toEdge: [.left,.right, .top, .bottom], withColor: color, inset: inset, thickness: thickness)
        }
        if edges.contains(.left) {
            addSidedBorder(toEdge: [.left], withColor: color, inset: inset, thickness: thickness)
        }
        if edges.contains(.right) {
            addSidedBorder(toEdge: [.right], withColor: color, inset: inset, thickness: thickness)
        }
        if edges.contains(.top) {
            addSidedBorder(toEdge: [.top], withColor: color, inset: inset, thickness: thickness)
        }
        if edges.contains(.bottom) {
            addSidedBorder(toEdge: [.bottom], withColor: color, inset: inset, thickness: thickness)
        }
    }

    private func addSidedBorder(toEdge edges: [RectangularEdges], withColor color: UIColor, inset: CGFloat = 0, thickness: CGFloat) {
        for Edge in edges {
            let border = BorderView(frame: .zero)
            border.backgroundColor = color
            addSubview(border)
            border.translatesAutoresizingMaskIntoConstraints = false
            switch Edge {
            case .left:
                NSLayoutConstraint.activate([
                border.leftAnchor.constraint(equalTo: self.leftAnchor, constant: inset),
                    border.topAnchor.constraint(equalTo: self.topAnchor, constant: inset),
                    border.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -inset),
                    NSLayoutConstraint(item: border, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .width, multiplier: 1, constant: thickness) ])
            case .right:
                NSLayoutConstraint.activate([
                    border.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -inset),
                    border.topAnchor.constraint(equalTo: self.topAnchor, constant: inset),
                    border.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -inset),
                    NSLayoutConstraint(item: border, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .width, multiplier: 1, constant: thickness) ])
            case .top:
                NSLayoutConstraint.activate([
                    border.leftAnchor.constraint(equalTo: self.leftAnchor, constant: inset),
                    border.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -inset),
                    border.topAnchor.constraint(equalTo: self.topAnchor, constant: inset),
                    NSLayoutConstraint(item: border, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: thickness) ])
            case .bottom:
                NSLayoutConstraint.activate([
                    border.leftAnchor.constraint(equalTo: self.leftAnchor, constant: inset),
                    border.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -inset),
                    border.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -inset),
                    NSLayoutConstraint(item: border, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: thickness) ])
            }
        }
    }

    private enum RectangularEdges {
        case left
        case right
        case top
        case bottom
    }
}
1
Andrej

На случай, если кому-то понадобится версия Xamarin:

public static class UIUtils
{
    public static void AddBorder(this CALayer cALayer, UIRectEdge Edge, UIColor color, float thickness)
    {

        var border = new CALayer();
        switch (Edge) 
        {
            case UIRectEdge.Top:
                border.Frame = new CGRect(0, 0, cALayer.Frame.Width, height: thickness);
                break;
            case UIRectEdge.Bottom:
                border.Frame = new CGRect(0, cALayer.Frame.Height - thickness, width: cALayer.Frame.Width, height: thickness);
                break;
            case UIRectEdge.Left:
                border.Frame = new CGRect(0, 0, width: thickness, height: cALayer.Frame.Height);
                break;
            case UIRectEdge.Right:
                border.Frame = new CGRect(cALayer.Frame.Width - thickness, y: 0, width: thickness, height: cALayer.Frame.Height);
                break;
            default: break;
        }
        border.BackgroundColor = color.CGColor;
        cALayer.AddSublayer(border);
    }
}
1
Array

Вы также можете проверить эту коллекцию категорий UIKit и Foundation: https://github.com/leszek-s/LSCategories

Это позволяет добавить границу на одной стороне UIView одной строкой кода:

[self.someView lsAddBorderOnEdge:UIRectEdgeTop color:[UIColor blueColor] width:2];

и он правильно обрабатывает поворот представления, в то время как большинство ответов, размещенных здесь, не справляются с этим хорошо.

0
Leszek Szary

Конвертировать DanShev ответить на Swift 3

extension CALayer {

func addBorder(Edge: UIRectEdge, color: UIColor, thickness: CGFloat) {

    let border = CALayer()

    switch Edge {
    case .top:
        border.frame = CGRect(x: 0, y: 0, width: self.frame.width, height: thickness)
        break
    case .bottom:
        border.frame = CGRect(x: 0, y: self.frame.height - thickness, width: self.frame.width, height: thickness)
        break
    case .left:
        border.frame = CGRect(x: 0, y: 0, width: thickness, height: self.frame.height)
        break
    case .right:
        border.frame = CGRect(x: self.frame.width - thickness, y: 0, width: thickness, height: self.frame.height)
        break
    default:
        break
    }

    border.backgroundColor = color.cgColor;

    self.addSublayer(border)
}
}
0
ADS

Лично мне нравится подклассы view + drawRect, но вот еще один способ сделать это (и он работает в том же духе, что и принятый ответ @If Pollavith):

Ваш новый пограничный слой может быть настроен так, чтобы иметь любые размеры, которые вам нравятся. Итак, как и в случае ответа @Flalavith, вы создаете слой, который будет таким же высоким, каким вы хотите его видеть, и таким широким, каким вы хотели бы ограничить вид. Используйте определение фрейма слоя, чтобы разместить его там, где вы хотите, а затем добавьте его в качестве подслоя к своему виду.

Для справки, мое собственное требование состояло в том, чтобы поместить границу на левую сторону вида (пожалуйста, не вырезайте и не вставляйте этот код, а просто «меня просто», потому что он не ставит границу наверху представления - изменение кода ниже достаточно просто):

    CALayer *leftBorder = [CALayer layer];
leftBorder.borderColor = [UIColor colorWithRed:0.0 green:91.0/255.0 blue:141.0/255.0 alpha:1.0].CGColor;
leftBorder.borderWidth = 1;
leftBorder.frame = CGRectMake(0, 0, 1.0, CGRectGetHeight(self.myTargetView.frame));
[self.myTargetView.layer addSublayer:leftBorder];

Я предполагаю, что единственное умеренное преимущество по сравнению с этим и создание небольшого UIView или UILabel состоит в том, что CALayer предположительно «легче», и есть много интересных представлений (как и во мнениях) о перегрузке drawRect по сравнению с использованием CALayers (как здесь : iOS: Использование UIView 'drawRect:' против delagate его слоя 'drawLayer: inContext:' ).

Animal451

Мне нравится синий цвет.

0
Animal451

В Свифт 4 и 3

let borderThickness = 2
let topBorder = UIView()
topBorder.backgroundColor = UIColor.red
topBorder.frame = CGRect(x: 0, y: 0, width: 
                  Int(yourViewFromOutlet.frame.size.width), height: 
                  borderThickness)
yourViewFromOutlet.addSubview(topBorder)
0
Naishta

Для Xamarin в C # я просто создаю встроенную границу при добавлении подслоя

  View.Layer.AddSublayer(new CALayer()
    {
        BackgroundColor = UIColor.Black.CGColor,
        Frame = new CGRect(0, 0, View.Frame.Width, 0.5f)
    });

Вы можете организовать это (как предложено другими) для нижней, левой и правой границ.

0
Craig Champion

Для меня работает

extension UIView {

    func addBorders(edges: UIRectEdge = .all, color: UIColor = .black, width: CGFloat = 1.0) {

        func createBorder() -> UIView {
            let borderView = UIView(frame: CGRect.zero)
            borderView.translatesAutoresizingMaskIntoConstraints = false
            borderView.backgroundColor = color
            return borderView
        }

        if (edges.contains(.all) || edges.contains(.top)) {
            let topBorder = createBorder()
            self.addSubview(topBorder)
            NSLayoutConstraint.activate([
                topBorder.topAnchor.constraint(equalTo: self.topAnchor),
                topBorder.leadingAnchor.constraint(equalTo: self.leadingAnchor),
                topBorder.trailingAnchor.constraint(equalTo: self.trailingAnchor),
                topBorder.heightAnchor.constraint(equalToConstant: width)
                ])
        }
        if (edges.contains(.all) || edges.contains(.left)) {
            let leftBorder = createBorder()
            self.addSubview(leftBorder)
            NSLayoutConstraint.activate([
                leftBorder.topAnchor.constraint(equalTo: self.topAnchor),
                leftBorder.bottomAnchor.constraint(equalTo: self.bottomAnchor),
                leftBorder.leadingAnchor.constraint(equalTo: self.leadingAnchor),
                leftBorder.widthAnchor.constraint(equalToConstant: width)
                ])
        }
        if (edges.contains(.all) || edges.contains(.right)) {
            let rightBorder = createBorder()
            self.addSubview(rightBorder)
            NSLayoutConstraint.activate([
                rightBorder.topAnchor.constraint(equalTo: self.topAnchor),
                rightBorder.bottomAnchor.constraint(equalTo: self.bottomAnchor),
                rightBorder.trailingAnchor.constraint(equalTo: self.trailingAnchor),
                rightBorder.widthAnchor.constraint(equalToConstant: width)
                ])
        }
        if (edges.contains(.all) || edges.contains(.bottom)) {
            let bottomBorder = createBorder()
            self.addSubview(bottomBorder)
            NSLayoutConstraint.activate([
                bottomBorder.bottomAnchor.constraint(equalTo: self.bottomAnchor),
                bottomBorder.leadingAnchor.constraint(equalTo: self.leadingAnchor),
                bottomBorder.trailingAnchor.constraint(equalTo: self.trailingAnchor),
                bottomBorder.heightAnchor.constraint(equalToConstant: width)
                ])
        }
    }
}
0
Vadym

Примечание: большинство решений здесь не являются адаптивными и не будут изменять размер. Решения, размер которых будет изменен, будут влиять на время запуска массово, так как они используют много ЦП.

Вы можете использовать это решение ниже. Он работает на 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. Установите цвет и ширину линии, используя yourview.color и yourview.lineWidth в вашем методе viewDidAppear
  3. Установите края, например: yourview.edges = [.right, .left] ([.all]) для всех
  4. Наслаждайтесь быстрым стартом и изменением размеров границ
0
J. Doe

Для настройки верхней границы и нижней границы для UIView в Swift.

let topBorder = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 1))
topBorder.backgroundColor = UIColor.black
myView.addSubview(topBorder)

let bottomBorder = UIView(frame: CGRect(x: 0, y: myView.frame.size.height - 1, width: 10, height: 1))
bottomBorder.backgroundColor = UIColor.black
myView.addSubview(bottomBorder)
0
Sudhi 9135

В дополнение к n8tr можно добавить, что есть возможность установить их из раскадровки:
- добавить два свойства, такие как borderColor и borderWidth в файл .h;
- тогда вы можете добавить keyPaths прямо в раскадровку, см. ссылку на скриншот

0
Mykhailo Lysenko