Is there a way to set the sides of the border of a UIView to one color and leave the top and the bottom another?
6 Answers
Nope—CALayer borders don’t support that behavior. The easiest way to accomplish what you want is adding an n-point-wide opaque subview with your desired border color as its background color on each side of your view.
Example:
CGSize mainViewSize = theView.bounds.size;
CGFloat borderWidth = 2;
UIColor *borderColor = [UIColor redColor];
UIView *leftView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, borderWidth, mainViewSize.height)];
UIView *rightView = [[UIView alloc] initWithFrame:CGRectMake(mainViewSize.width - borderWidth, 0, borderWidth, mainViewSize.height)];
leftView.opaque = YES;
rightView.opaque = YES;
leftView.backgroundColor = borderColor;
rightView.backgroundColor = borderColor;
// for bonus points, set the views' autoresizing mask so they'll stay with the edges:
leftView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleRightMargin;
rightView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin;
[theView addSubview:leftView];
[theView addSubview:rightView];
[leftView release];
[rightView release];
Note that this won’t quite match the behavior of CALayer borders—the left and right border views will always be inside the boundaries of their superview.

- 57,021
- 16
- 130
- 131
The answer with the views that works like borders are very nice, but remember that every view is a UI Object that cost lots of memory.
I whould use uivew's layer to paint a stroke with color on an already existing UIview.
-(CAShapeLayer*)drawLineFromPoint:(CGPoint)fromPoint toPoint:(CGPoint) toPoint withColor:(UIColor *)color andLineWidth:(CGFloat)lineWidth{
CAShapeLayer *lineShape = nil;
CGMutablePathRef linePath = nil;
linePath = CGPathCreateMutable();
lineShape = [CAShapeLayer layer];
lineShape.lineWidth = lineWidth;
lineShape.strokeColor = color.CGColor;
NSUInteger x = fromPoint.x;
NSUInteger y = fromPoint.y;
NSUInteger toX = toPoint.x;
NSUInteger toY = toPoint.y;
CGPathMoveToPoint(linePath, nil, x, y);
CGPathAddLineToPoint(linePath, nil, toX, toY);
lineShape.path = linePath;
CGPathRelease(linePath);
return lineShape;}
and add it to our view.
CAShapeLayer* borderLine=[self drawLineFromPoint:CGPointMake(0, 0) toPoint:CGPointMake(0,_myView.frame.size.height) withColor:[UIColor lightGrayColor] andLineWidth:1.0f];
[_myView.layer addSublayer:borderLine];
So... We take a point and actually painting a line from top to the bottom of our view. The result is that there is a line that looks like a one pixel width border.

- 3,538
- 3
- 16
- 10
Updated for Swift 3.0
I wrote a Swift extension (for a UIButton) that simulates setting a border on any side of a UIView to a given color and width. It's similar to @Noah Witherspoon's approach, but self-contained and autolayout constraint based.
// Swift 3.0
extension UIView {
enum Border {
case left
case right
case top
case bottom
}
func setBorder(border: UIView.Border, weight: CGFloat, color: UIColor ) {
let lineView = UIView()
addSubview(lineView)
lineView.backgroundColor = color
lineView.translatesAutoresizingMaskIntoConstraints = false
switch border {
case .left:
lineView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
lineView.topAnchor.constraint(equalTo: topAnchor).isActive = true
lineView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
lineView.widthAnchor.constraint(equalToConstant: weight).isActive = true
case .right:
lineView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
lineView.topAnchor.constraint(equalTo: topAnchor).isActive = true
lineView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
lineView.widthAnchor.constraint(equalToConstant: weight).isActive = true
case .top:
lineView.topAnchor.constraint(equalTo: topAnchor).isActive = true
lineView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
lineView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
lineView.heightAnchor.constraint(equalToConstant: weight).isActive = true
case .bottom:
lineView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
lineView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
lineView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
lineView.heightAnchor.constraint(equalToConstant: weight).isActive = true
}
}
}

- 4,696
- 2
- 33
- 57
-
1Second line of .Right should contain `lineView.rightAnchor`: `lineView.rightAnchor.constraintEqualToAnchor(self.rightAnchor, constant: 0).active = true` – Arthur Clemens Jul 10 '16 at 12:48
-
@ArthurClemens you're right. Thanks for spotting that :) – 0x6A75616E Jul 12 '16 at 00:04
-
I'm not sure what `theWeight` does, but taking that line out seems to still have the desired effect. – Maxwell Mar 23 '17 at 20:04
-
This extension does not account for being called multiple times. It always adds another border over the existing borders, but should check for existing borders and remove them if necessary. Also it should be possible to remove borders, not only add them. All in all this is a rocky one-way street. – Manuel Feb 04 '18 at 14:42
This sounds like one of two answers:
If your view is a static size, then just put a UIView behind it that is 2 pixels wider and 2 pixels shorter than your front view.
If it is non-static sized then you could do the same, resizing the backing view whenever your foreground view is resized, or implement a custom object that implements a UIView, and implement (override) your own drawRect routine.

- 7,033
- 2
- 19
- 33
NAUIViewWithBorders did the trick for me. See also the creator's SO post here. Worth checking out if you need this functionality for more than a couple views.
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
}
}
// set properties on existing view, or create a new one
if newView == nil {
newView = UIView(frame: layerFrame)
newView?.tag = borderType.rawValue
self.addSubview(newView!)
} else {
newView?.frame = layerFrame
}
newView?.backgroundColor = color
newView?.autoresizingMask = autoresizingMask
}

- 503
- 7
- 9