43

I know how to add border to a button in iOS 7, with the following code :

[[myButton layer] setBorderColor:[[[UIColor grayColor] colorWithAlphaComponent:0.5] CGColor]];
[[myButton layer] setBorderWidth:1];
[[myButton layer] setCornerRadius:15];

But how can I add just one border ? I want to add only the top border.

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Jonathan F.
  • 2,357
  • 4
  • 26
  • 44

11 Answers11

69
UIView *lineView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, btn.frame.size.width, 1)];
lineView.backgroundColor = [UIColor redColor];
[btn addSubview:lineView];

you can do the same for each border. Adding multiple UIViews you can add bottom and left or top and right or any border you want.

i.e. bottom & left:

UIView *bottomBorder = [[UIView alloc] initWithFrame:CGRectMake(0, btn.frame.size.height - 1.0f, btn.frame.size.width, 1)];
bottomBorder.backgroundColor = [UIColor redColor];

UIView *leftBorder = [[UIView alloc] initWithFrame:CGRectMake(1, 0, 1, btn.frame.size.height)];
leftBorder.backgroundColor = [UIColor redColor];

[btn addSubview:bottomBorder];
[btn addSubview:leftBorder];

if you don't use ARC, remember to release UIViews after adding subviews (or use autorelease).

masgar
  • 1,875
  • 2
  • 20
  • 32
  • @Chris.Jenkins it is very strange it doesn't work. It should works with any type of UIButton, from IB or programmatically. It siply add a subview with button width and 1px height. Try to check button and lineview frame by logging them: NSLog(@"btn frame: %@", NSStringFromCGRect(btn.frame)); – masgar Mar 06 '14 at 14:37
  • 1
    How to remove this border view on runtime? Ex: When button action is triggered i need to remove that border. Please reply. @masgar – Mohd Sadham Dec 28 '16 at 09:51
  • you can set a tag to each view and remove view with tag from superview. – masgar Jul 03 '17 at 22:02
  • how can i add shadow on border ? @masgar – Shourob Datta Aug 16 '18 at 16:35
  • there are tons of answer about shadow. The border you add is a view and you can add shadow to a view by using QuartzCore. check tis answer: https://stackoverflow.com/questions/805872/how-do-i-draw-a-shadow-under-a-uiview – masgar Aug 16 '18 at 22:28
24

Here is masgar's solution implemented in Swift:

var lineView = UIView(frame: CGRectMake(0, 0, btn.frame.size.width, 1))
lineView.backgroundColor=UIColor.redColor()
btn.addSubview(lineView)
Olcay Ertaş
  • 5,987
  • 8
  • 76
  • 112
peacetype
  • 1,928
  • 3
  • 29
  • 49
  • How to remove this border view on runtime? Ex: When button action is triggered i need to remove that border. Please reply. – Mohd Sadham Dec 28 '16 at 09:51
  • I haven't checked this myself yet but try lineView.removeFromSuperview() See this for more information, as I may have gotten it wrong: http://stackoverflow.com/q/28197079/4376309 – peacetype Dec 28 '16 at 17:39
21

In Swift add an extension for UIView class like this:

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

I got this extension from this link:UIView bottom border?

Then call the function like this

var innerView : UIView?
let borderWidth: CGFloat = 1.0
let borderColor : UIColor =  UIColor.redColor()
innerView!.addTopBorderWithColor(borderColor, width: borderWidth)

For adaptive layout use this one

extension UIView {

    func addTopBorder(_ color: UIColor, height: CGFloat) {
        let border = UIView()
        border.backgroundColor = color
        border.translatesAutoresizingMaskIntoConstraints = false
        self.addSubview(border)
        border.addConstraint(NSLayoutConstraint(item: border,
            attribute: NSLayoutAttribute.height,
            relatedBy: NSLayoutRelation.equal,
            toItem: nil,
            attribute: NSLayoutAttribute.height,
            multiplier: 1, constant: height))
        self.addConstraint(NSLayoutConstraint(item: border,
            attribute: NSLayoutAttribute.top,
            relatedBy: NSLayoutRelation.equal,
            toItem: self,
            attribute: NSLayoutAttribute.top,
            multiplier: 1, constant: 0))
        self.addConstraint(NSLayoutConstraint(item: border,
            attribute: NSLayoutAttribute.leading,
            relatedBy: NSLayoutRelation.equal,
            toItem: self,
            attribute: NSLayoutAttribute.leading,
            multiplier: 1, constant: 0))
        self.addConstraint(NSLayoutConstraint(item: border,
            attribute: NSLayoutAttribute.trailing,
            relatedBy: NSLayoutRelation.equal,
            toItem: self,
            attribute: NSLayoutAttribute.trailing,
            multiplier: 1, constant: 0))
    }

    func addBottomBorder(_ color: UIColor, height: CGFloat) {
        let border = UIView()
        border.backgroundColor = color
        border.translatesAutoresizingMaskIntoConstraints = false
        self.addSubview(border)
        border.addConstraint(NSLayoutConstraint(item: border,
            attribute: NSLayoutAttribute.height,
            relatedBy: NSLayoutRelation.equal,
            toItem: nil,
            attribute: NSLayoutAttribute.height,
            multiplier: 1, constant: height))
        self.addConstraint(NSLayoutConstraint(item: border,
            attribute: NSLayoutAttribute.bottom,
            relatedBy: NSLayoutRelation.equal,
            toItem: self,
            attribute: NSLayoutAttribute.bottom,
            multiplier: 1, constant: 0))
        self.addConstraint(NSLayoutConstraint(item: border,
            attribute: NSLayoutAttribute.leading,
            relatedBy: NSLayoutRelation.equal,
            toItem: self,
            attribute: NSLayoutAttribute.leading,
            multiplier: 1, constant: 0))
        self.addConstraint(NSLayoutConstraint(item: border,
            attribute: NSLayoutAttribute.trailing,
            relatedBy: NSLayoutRelation.equal,
            toItem: self,
            attribute: NSLayoutAttribute.trailing,
            multiplier: 1, constant: 0))
    }

    func addLeftBorder(_ color: UIColor, width: CGFloat) {
        let border = UIView()
        border.backgroundColor = color
        border.translatesAutoresizingMaskIntoConstraints = false
        self.addSubview(border)
        border.addConstraint(NSLayoutConstraint(item: border,
            attribute: NSLayoutAttribute.width,
            relatedBy: NSLayoutRelation.equal,
            toItem: nil,
            attribute: NSLayoutAttribute.width,
            multiplier: 1, constant: width))
        self.addConstraint(NSLayoutConstraint(item: border,
            attribute: NSLayoutAttribute.leading,
            relatedBy: NSLayoutRelation.equal,
            toItem: self,
            attribute: NSLayoutAttribute.leading,
            multiplier: 1, constant: 0))
        self.addConstraint(NSLayoutConstraint(item: border,
            attribute: NSLayoutAttribute.bottom,
            relatedBy: NSLayoutRelation.equal,
            toItem: self,
            attribute: NSLayoutAttribute.bottom,
            multiplier: 1, constant: 0))
        self.addConstraint(NSLayoutConstraint(item: border,
            attribute: NSLayoutAttribute.top,
            relatedBy: NSLayoutRelation.equal,
            toItem: self,
            attribute: NSLayoutAttribute.top,
            multiplier: 1, constant: 0))
    }

    func addRightBorder(_ color: UIColor, width: CGFloat) {
        let border = UIView()
        border.backgroundColor = color
        border.translatesAutoresizingMaskIntoConstraints = false
        self.addSubview(border)
        border.addConstraint(NSLayoutConstraint(item: border,
            attribute: NSLayoutAttribute.width,
            relatedBy: NSLayoutRelation.equal,
            toItem: nil,
            attribute: NSLayoutAttribute.width,
            multiplier: 1, constant: width))
        self.addConstraint(NSLayoutConstraint(item: border,
            attribute: NSLayoutAttribute.trailing,
            relatedBy: NSLayoutRelation.equal,
            toItem: self,
            attribute: NSLayoutAttribute.trailing,
            multiplier: 1, constant: 0))
        self.addConstraint(NSLayoutConstraint(item: border,
            attribute: NSLayoutAttribute.bottom,
            relatedBy: NSLayoutRelation.equal,
            toItem: self,
            attribute: NSLayoutAttribute.bottom,
            multiplier: 1, constant: 0))
        self.addConstraint(NSLayoutConstraint(item: border,
            attribute: NSLayoutAttribute.top,
            relatedBy: NSLayoutRelation.equal,
            toItem: self,
            attribute: NSLayoutAttribute.top,
            multiplier: 1, constant: 0))
    }
}

Usage:

button!.addTopBorder(UIColor(red: 247.0/255.0, green: 147.0/255.0, blue: 29.0/255.0, alpha: 0.5), height: borderWidth)
Kiran P Nair
  • 2,041
  • 22
  • 31
13

Swift 4

UIButton Top Border

var lineView = UIView(frame: CGRect(x: 0, y: 0, width: button.frame.size.width, height: 2))
lineView.backgroundColor= UIColor.black
button.addSubview(lineView)

UIButton Bottom Border

var lineView = UIView(frame: CGRect(x: 0, y: button.frame.size.height, width: button.frame.size.width, height: 2))
lineView.backgroundColor= UIColor.black
button.addSubview(lineView)
shim
  • 9,289
  • 12
  • 69
  • 108
Barath
  • 1,656
  • 19
  • 19
5

Just draw the border yourself:

@implementation TopBorderButton
- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
    CGContextFillRect(context, CGRectMake(0.0f, 0.0, self.frame.size.width, 1.0));
}
@end
Danyun Liu
  • 3,072
  • 24
  • 22
4

Actually I meet this questions as you,but I think my method is better than the answer which you choose. You should create a class inherit the UIControl like UIButton.

@interface customButton : UIButton

and rewrite the drawrect method like this:

- (void)drawRect:(CGRect)rect {
    // Drawing code
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetLineCap(context, kCGLineCapRound);
    CGContextSetLineWidth(context, 1.5);  //线宽
    CGContextSetAllowsAntialiasing(context, true);
    CGContextSetRGBStrokeColor(context, 193/255.0, 205/255.0, 193/255.0, 1.0);  //线的颜色
    CGContextBeginPath(context);

    CGContextMoveToPoint(context, 0, 0);  //起点坐标
    CGContextAddLineToPoint(context, self.frame.size.width, 0);   //终点坐标

    CGContextStrokePath(context);
}

By the way~ your purpose UIControl should use your class in xib's setting

[![this setting][1]][1]

Last~ show you my custom UIButton. I think we should choose this method and combine UIBezierPath's API to finish our demand.

[![enter image description here][2]][2]

Thank you for watching~ hope to study and discuss together~ From a iOS fisherman -- vvlong [1]: https://i.stack.imgur.com/ywIZk.png [2]: https://i.stack.imgur.com/mmfOB.png

Olcay Ertaş
  • 5,987
  • 8
  • 76
  • 112
long vv
  • 51
  • 1
  • 3
3

If you use constraints then you can add a border view with the required constraints

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

Then set it something like the below

myButton.addBorder(side: .left, color: UIColor.lightGray, width: 1)

(inspired by this answer)

Inti
  • 3,443
  • 1
  • 29
  • 34
  • 1
    Excellent answer. Only 1 line of code is needed by a caller along with using a consistent enum for sides. Well done. – Nick N Dec 03 '20 at 19:06
2

You can't using this layer methods.
The best solution here is create a small image (by code or photoshop), use the - (UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets resizingMode:(UIImageResizingMode)resizingMode to resize it according to the aspect that you want give and add it as a background image. This is really a good approach because it helps you to keep a very small memory footprint and that adapts your image to all button sizes.
Here a good tutorial.

Andrea
  • 26,120
  • 10
  • 85
  • 131
0

You have to create a new layer or view 1pt high, set its background color to the color you want your border, and add it as a subview/sublayer.

Kevin
  • 53,822
  • 15
  • 101
  • 132
-1

If you need anything other than the default, you need to manually draw it.

Maxthon Chan
  • 1,181
  • 8
  • 15
-1

Best and simple way....

btnTest.selectiveBorderFlag = AUISelectiveBordersFlagBottom | AUISelectiveBordersFlagTop;
btnTest.selectiveBordersColor = [UIColor redColor];
btnTest.selectiveBordersWidth = 3.0;

Have did it using : this open source code

Himanshu padia
  • 7,428
  • 1
  • 47
  • 45