9

good morning together,

i have a tableview like this: enter image description here

Example: in cell one i have got an red text label on the right side. left from it i include an image like a grey line.

with this code i can set a complete green border:

    cell.Label.layer.borderWidth = 0.5
    cell.Label.layer.borderColor = UIColor.greenColor().CGColor

can i set only a border on the left side from this text label? i use swift ios8 - so, i need a swift solution

Trombone0904
  • 4,132
  • 8
  • 51
  • 104

6 Answers6

42

Here is an extension you can add to your project:

extension CALayer {

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

        var border = CALayer()

        switch edge {
        case UIRectEdge.Top:
            border.frame = CGRectMake(0, 0, CGRectGetHeight(self.frame), thickness)
            break
        case UIRectEdge.Bottom:
            border.frame = CGRectMake(0, CGRectGetHeight(self.frame) - thickness, UIScreen.mainScreen().bounds.width, 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)
    }

}

And the use it like this:

cell.Label.layer.addBorder(UIRectEdge.Top, color: UIColor.greenColor(), thickness: 0.5)

FOR SWIFT 3, 4 & 5:


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.height, height: thickness)
            break
        case UIRectEdge.bottom:
            border.frame = CGRect(x: 0, y: self.frame.height - thickness, width: UIScreen.main.bounds.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)
    }

}
PhillipJacobs
  • 2,337
  • 1
  • 16
  • 32
Maysam
  • 7,246
  • 13
  • 68
  • 106
  • thank you very much for this solution. it works fine. but one question more: is there an option to change the space between the left border and the label? i want more space – Trombone0904 Aug 31 '15 at 17:34
  • Read this: http://stackoverflow.com/questions/27459746/adding-space-padding-to-a-uilabel-swift – Maysam Sep 01 '15 at 06:45
  • Just a heads-up that your top border is using the view's height for the width setting, so unless the target view is a square, the top border will be too short. It should be changed to `border.frame = CGRectMake(0, 0, CGRectGetWidth(self.frame), thickness)` – Timothy Aug 18 '16 at 16:23
  • This works great. I'm trying to remove it when selected, but can't seem to figure it out. I tried this `cell.layer.sublayers?.forEach {$0.removeFromSuperlayer() }`but it causes problems because it removes everything else in the view. – Coder1224 Oct 05 '16 at 22:07
18

Swift 3 version:

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

}

Or use IBDesignable (see answer below)

Tom
  • 874
  • 7
  • 13
3

Swift 4 Version:

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.bounds.width, height: thickness)

            case UIRectEdge.bottom:
             border.frame = CGRect(x: 0, y: self.bounds.height - thickness,  width: self.bounds.width, height: thickness)

            case UIRectEdge.left:
             border.frame = CGRect(x: 0, y: 0,  width: thickness, height: self.bounds.height)

            case UIRectEdge.right:
             border.frame = CGRect(x: self.bounds.width - thickness, y: 0,  width: thickness, height: self.bounds.height)

            default:
             break
        }
        border.backgroundColor = color.cgColor;
        self.addSublayer(border)
    }
}
emma ray
  • 13,336
  • 1
  • 24
  • 50
Kunal Shah
  • 1,071
  • 9
  • 24
1

These solutions worked for me, however I was using tableview rows and the height of the row was dynamically set based on how much content was in the rows.

For the above solutions I found that if the size of the row was dynamically increased because of the content within the row, the border's size didn't increase. So I had an incomplete border on rows that were larger than normal.

I came across this solution from @Debaprio B at this link (Oct 11, 2017 post): UIView set only side borders

His solution worked for me, and the border's sized changed appropriately when my row's size increased dynamically. I'm sharing @Debaprio's answer below for brevity:


public extension UIView {
// Border type and arbitrary tag values to identify UIView borders as subviews

public enum BorderType: Int {
case left = 20000
case right = 20001
case top = 20002
case bottom = 20003
}

public func addBorder(borderType: BorderType, width: CGFloat, color: UIColor {
// figure out frame and resizing based on border type
var autoresizingMask: UIViewAutoresizing
var layerFrame: CGRect

switch borderType {

case .left:
    layerFrame = CGRect(x: 0, y: 0, width: width, height: self.bounds.height)
    autoresizingMask = [ .flexibleHeight, .flexibleRightMargin ]
case .right:
    layerFrame = CGRect(x: self.bounds.width - width, y: 0, width: width, height: self.bounds.height)
    autoresizingMask = [ .flexibleHeight, .flexibleLeftMargin ]
case .top:
    layerFrame = CGRect(x: 0, y: 0, width: self.bounds.width, height: width)
    autoresizingMask = [ .flexibleWidth, .flexibleBottomMargin ]
case .bottom:
    layerFrame = CGRect(x: 0, y: self.bounds.height - width, width: self.bounds.width, height: width)
    autoresizingMask = [ .flexibleWidth, .flexibleTopMargin ]
}

// look for the existing border in subviews
var newView: UIView?
for eachSubview in self.subviews {
    if eachSubview.tag == borderType.rawValue {
        newView = eachSubview
        break
    }
}
Andrew
  • 619
  • 1
  • 7
  • 10
0

Apart from using an extension, you can also use @IBDesignable / @IBInspectable to create a subclass from UILabel and draw the border there. This has some advantages, because you can then use the Interface Builder to style your label and it is shown directly in the Storyboard.

@IBDesignable
class LeftBorderedLabel: UILabel {

    @IBInspectable var blockColor: UIColor = UIColor.black {

        didSet{

            let border = CALayer()
            border.frame = CGRect(x: 0, y: 0, width: 15, height: self.frame.height)
            border.backgroundColor = blockColor.cgColor;

            self.layer.addSublayer(border)
        }
    }

    override func prepareForInterfaceBuilder() {

        super.prepareForInterfaceBuilder()
    }
}

Example in interface builder (example is for a tableViewCell):

Interface builder example

Tom
  • 874
  • 7
  • 13
-1

Here is an extension you can add to your project.

SWIFT 3 :-

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:
            //For Center Line
            border.frame = CGRect(x: self.frame.width/2 - thickness, y: 0, width: thickness, height: self.frame.height)
            break
        }

        border.backgroundColor = color.cgColor;
        self.addSublayer(border)
    }
}

And the use it like this:

labelName.layer.addBorder(edge: UIRectEdge.right, color: UIColor.black, thickness: 1.5)

If you want to draw a line on Center, then you can set following frame in any of the scenario :-

border.frame = CGRect(x: self.frame.width/2 - thickness, y: 0, width: thickness, height: self.frame.height)
Meet Doshi
  • 4,241
  • 10
  • 40
  • 81