UIView set only side borders
Solution 1
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.
Solution 2
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
}
}
}
Solution 3
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.
Solution 4
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.
Mason
Updated on October 12, 2020Comments
-
Mason over 3 years
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?
-
Arthur Clemens almost 8 yearsSecond line of .Right should contain
lineView.rightAnchor
:lineView.rightAnchor.constraintEqualToAnchor(self.rightAnchor, constant: 0).active = true
-
0x6A75616E almost 8 years@ArthurClemens you're right. Thanks for spotting that :)
-
Maxwell about 7 yearsI'm not sure what
theWeight
does, but taking that line out seems to still have the desired effect. -
Manuel about 6 yearsThis 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.