18

i try to add border for a uilabel, but i only want to have top, right, and bottom border.

like this

           ----------------
                          |
            I am a label  |
                          |
           ----------------

I try to use these codes, but it adds all 4 sides by default

    myLabel.layer.borderWidth = 1;
    myLabel.layer.borderColor = [UIColor blackColor];

Is that anyway i can only add 3 sides, or even 1 or 2 sides?

Thanks!

Xu Yin
  • 3,932
  • 1
  • 26
  • 46
user3276557
  • 211
  • 1
  • 2
  • 5
  • Honestly, there's nothing wrong with adding three thin, black UIView - it is very easy with autolayout. – Fattie Jul 22 '17 at 02:23

9 Answers9

28

You can use a mask. This is the code I used to test the theory, and it works well:

// Define the border width in a variable, we'll be using it elsewhere
CGFloat borderWidth = 1.0;

// This creates a testing view to test the theory, in your case this will be your UILabel
UIView* view = [[UIView alloc] initWithFrame:CGRectMake(20, 60, 250, 100)];
view.layer.borderColor = [UIColor blackColor].CGColor;
view.layer.borderWidth = borderWidth;
[self.view addSubview:view];

// Create the mask to cover the area of the view you want to **show**
// Here, we create a mask that covers most of the view, except the left edge
// The mask needs to be coloured in black, as black acts as transparent, whereas white is opaque in mask parlance
UIView* mask = [[UIView alloc] initWithFrame:CGRectMake(borderWidth, 0, view.frame.size.width - borderWidth, view.frame.size.height)];
mask.backgroundColor = [UIColor blackColor];
view.layer.mask = mask.layer;

You can adjust the size and position of the mask (given the borderWidth) to show/hide the border edges you're interested in. The example above hides the left edge.

WDUK
  • 18,870
  • 3
  • 64
  • 72
  • This looks great to me, Thank you. I would love to vote you up if i have 15 reputations.. – user3276557 Feb 05 '14 at 19:24
  • @user3276557 It's better than other solutions listed as this leaves the border drawing to the CoreGraphics framework, and doesn't pollute your view hierarchy with other views. The mask is optimised, and hence will get better performance. (So not sure why is no longer the accepted answer...) – WDUK Feb 05 '14 at 19:33
  • 1
    Oh, i am so sorry,i am very new to Stackoverflow, i thought i could accept both your answer and Mikael's answer. Your answer is better. maybe i should just vote up if i have enough reputation... – user3276557 Feb 05 '14 at 19:40
  • 2
    How do I implement this in Swift? – Nagendra Rao Sep 07 '15 at 10:15
  • In Swift use this: let view = UIView(frame: CGRectMake(20,60 , 250, 100)) view.layer.borderColor = UIColor.blueColor().CGColor; view.layer.borderWidth = borderWidth; self.view.addSubview(view) let mask = UIView(frame: CGRectMake(borderWidth, 0, view.frame.size.width - borderWidth, view.frame.size.height)) // mask.backgroundColor = UIColor.blackColor() view.layer.mask = mask.layer; – Kiran P Nair May 03 '16 at 07:27
  • http://stackoverflow.com/questions/19890956/how-to-add-only-a-top-border-on-a-uibutton/36998554#36998554 – Kiran P Nair May 03 '16 at 10:02
7

You'll have to adjust sizes but this is the gist of it. (might be some typos)

UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 35)];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 15, 320, 20)];

CALayer *bottomBorder = [CALayer layer];
bottomBorder.frame = CGRectMake(0, 40, 320, .5);

CALayer *rightBorder = [CALayer layer];
rightBorder.frame = CGRectMake(320, 0, 40, .5);

CALayer *topBorder = [CALayer layer];
topBorder.frame = CGRectMake(0, 0, 320, .5);

[view.layer addSublayer:bottomBorder];
[view.layer addSublayer:topBorder];
[view.layer addSublayer:rightBorder];
[view.layer addSublayer:label];
Mika
  • 5,807
  • 6
  • 38
  • 83
  • I think i only want to have it on my label, since i have about 6 on one view controller. in your code, i might have to create another 6 uiviews, but thank you for your idea. – user3276557 Feb 05 '14 at 19:23
  • Just remove the view it's the same. I just think it's neater with the view. – Mika Feb 05 '14 at 19:24
7

You can draw your three sides with one line by creating a CALayer that uses a UIBezierPath. With all of the examples, include the QuartzCore framework as part of your project.

Following your original code as a starting point:

// at the top of the file with this code, include:
#import <QuartzCore/QuartzCore.h>

CGRect rect = myLabel.frame;

UIBezierPath * linePath = [UIBezierPath bezierPath];

// start at top left corner
[linePath moveToPoint:CGPointMake(0,0);
// draw top line across
[linePath addLineToPoint:CGPointMake(rect.size.width, 0);
// draw right vertical side
[linePath addLineToPoint:CGPointMake(rect.size.width, rect.size.height);
// draw left vertical side
[linePath addLineToPoint:CGPointMake(0, rect.size.height);

// draw from bottom right corner back to bottom left corner
[linePath addLineToPoint:CGPointMake(0, rect.size.height);

// create a layer that uses your defined path
CAShapeLayer * lineLayer = [CAShapeLayer layer];
lineLayer.lineWidth = 1.0;
lineLayer.strokeColor = [UIColor blackColor].CGColor;

lineLayer.fillColor = nil;
lineLayer.path = linePath.CGPath;

[myLabel.layer addSublayer:lineLayer];
alkar
  • 5,459
  • 7
  • 27
  • 43
Mark Semsel
  • 7,125
  • 3
  • 29
  • 27
6

I'm using Swift 3.

// myLabel is a UILabel
let frame = myLabel.frame //Frame of label

// Bottom Layer
let bottomLayer = CALayer()
bottomLayer.frame = CGRect(x: 0, y: frame.height - 1, width: frame.width, height: 1)
bottomLayer.backgroundColor = UIColor.black.cgColor
myLabel.layer.addSublayer(bottomLayer)

// Top Layer
let topLayer = CALayer()
topLayer.frame = CGRect(x: 0, y: 0, width: frame.width, height: 1)
topLayer.backgroundColor = UIColor.black.cgColor
myLabel.layer.addSublayer(topLayer)

Similarly:

// Right Layer
let rightLayer = CALayer()
rightLayer.frame = CGRect(x: frame.width - 1, y: 0, width: 1, height: frame.height)
rightLayer.backgroundColor = UIColor.black.cgColor
myLabel.layer.addSublayer(rightLayer)

Where 1 is the width of the border.

Massimiliano Kraus
  • 3,638
  • 5
  • 27
  • 47
jaiswal Rajan
  • 4,641
  • 1
  • 27
  • 16
1

Here you guys go! Hope this helps, Add this inside UItextfield override class

UIView *view = [[UIView alloc] init];
view.translatesAutoresizingMaskIntoConstraints = NO;
view.layer.borderWidth = 1;
view.backgroundColor = [UIColor blackColor];
[self addSubview:view];

[self addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0.0]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeHeight multiplier:1.0 constant:1.0]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:1.0]];
Travis Delly
  • 1,194
  • 2
  • 11
  • 20
1

Thanks @jaiswal, i used your code and created a function, because i had more than 10 UILabels. I have put it here for reference.

 func buttomBoarder(label: UILabel) -> UILabel {
    let frame = label.frame

    let bottomLayer = CALayer()
    bottomLayer.frame = CGRect(x: 0, y: frame.height - 1, width: frame.width, height: 1)
    bottomLayer.backgroundColor = UIColor.black.cgColor
    label.layer.addSublayer(bottomLayer)

    return label

}

Called using

labelName = buttomBoarder(label: labelName)
alpha47
  • 305
  • 3
  • 17
0

You can subclass UILabel and override drawRect: to do that.

Or you could just make 3 UIView's with black background as subviews of this label. If you set autoresizingMask on them properly they will adjust to changes in the size of the label. Top border should have flexible width and flexible bottom margin, bottom border should have flexible width and flexible top margin, right border should have flexible height and flexible left margin.

johnyu
  • 2,152
  • 1
  • 15
  • 33
0

You can do it with multiple ways: 1st one is the easiest one just find a image that looks like your border strokes. Then add it an UIImageView back of your UILabel. 2nd way is override UILabel drawRect: then draw the stoke according to your needs.

csk
  • 418
  • 1
  • 5
  • 11
0

Simple extension on uilabel can solve the issue import UIKit

extension UILabel {
    
    func bottomBorder(with borderColor: UIColor, and borderWidth: CGFloat = 1.0){
        let bottomBorder = CALayer()
        bottomBorder.frame = CGRect(x: 0, y: self.frame.size.height - borderWidth, width: self.frame.size.width, height:borderWidth)
        bottomBorder.backgroundColor = borderColor.cgColor
        self.layer.addSublayer(bottomBorder)
    }
}