CALayer: add a border only at one side

63,405

Solution 1

I made a right border using this:

leftScrollView.clipsToBounds = YES;

CALayer *rightBorder = [CALayer layer];
rightBorder.borderColor = [UIColor darkGrayColor].CGColor;
rightBorder.borderWidth = 1;
rightBorder.frame = CGRectMake(-1, -1, CGRectGetWidth(leftScrollView.frame), CGRectGetHeight(leftScrollView.frame)+2);

[leftScrollView.layer addSublayer:rightBorder];

Solution 2

The easiest way is to add a subLayer that will draw the selective borders, but there are some things to consider when choosing this solution, the biggest are making sure that the borders subLayer is always on top, and that the borders change when you change the frame of your layer.

I implemented a drop in open source solution that takes care of those issues, and let you declare selective borders like this:

myView.borderDirection = AUIFlexibleBordersDirectionRight | AUIFlexibleBordersDirectionTop;

You can get the code, and read about it some more here

Solution 3

My Swift Solution. It involves four different functions, all extensions to UIView. Each function adds a different border.

extension UIView {
@discardableResult func addRightBorder(color: UIColor, width: CGFloat) -> UIView {
    let layer = CALayer()
    layer.borderColor = color.cgColor
    layer.borderWidth = width
    layer.frame = CGRect(x: self.frame.size.width-width, y: 0, width: width, height: self.frame.size.height)
    self.layer.addSublayer(layer)
    return self
    }
@discardableResult func addLeftBorder(color: UIColor, width: CGFloat) -> UIView {
    let layer = CALayer()
    layer.borderColor = color.cgColor
    layer.borderWidth = width
    layer.frame = CGRect(x: 0, y: 0, width: width, height: self.frame.size.height)
    self.layer.addSublayer(layer)
    return self
    }
@discardableResult func addTopBorder(color: UIColor, width: CGFloat) -> UIView {
    let layer = CALayer()
    layer.borderColor = color.cgColor
    layer.borderWidth = width
    layer.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: width)
    self.layer.addSublayer(layer)
    return self
    }
@discardableResult func addBottomBorder(color: UIColor, width: CGFloat) -> UIView {
    let layer = CALayer()
    layer.borderColor = color.cgColor
    layer.borderWidth = width
    layer.frame = CGRect(x: 0, y: self.frame.size.height-width, width: self.frame.size.width, height: width)
    self.layer.addSublayer(layer)
    return self
    }
}

Solution 4

The border property always add border to 4 sides of your view. You can make your own draw method to draw the border at the bottom of your view.

But, why don't you just add a view above your UIWebView to make it looks like a border?

Solution 5

Here's the swift equivalent

leftScrollView.clipsToBounds = true
let rightBorder: CALayer = CALayer()
rightBorder.borderColor = UIColor.darkGrayColor().CGColor
rightBorder.borderWidth = 1
rightBorder.frame = CGRectMake(-1, -1, CGRectGetWidth(leftScrollView.frame), CGRectGetHeight(leftScrollView.frame)+2)
leftScrollView.layer.addSublayer(rightBorder)
Share:
63,405
Manni
Author by

Manni

mobile development

Updated on January 29, 2020

Comments

  • Manni
    Manni over 4 years

    I can add a border to a CALayer in this way:

    [webView.layer setBorderColor: [[UIColor colorWithRed:0.6 green:0.7 blue:0.2 alpha:1] CGColor]];
    [webView.layer setBorderWidth: 2.75];   
    

    But is it possible to add a border only at one side? I only need a border at the bottom. Or can I reach this with other properties, e.g. frame, bounds, mask, ...?

    enter image description here

    Thanks for your help!


    @Control-V

            UIWebView *webView = [[UIWebView alloc] init];
            CALayer *webViewLayer = webView.layer;
    
            // now you can do a lot of stuff like borders:
            [webViewLayer setBorderColor: [[UIColor greenColor] CGColor]];
            [webViewLayer setBorderWidth: 2.75];    
    

    Have a look at the CALayer documentation: https://developer.apple.com/documentation/quartzcore/calayer

    And have a look here: http://iosdevelopertips.com/cocoa/add-rounded-corners-and-border-to-uiwebview.html

  • Manni
    Manni over 12 years
    Thank you for your reply, I will have a look on your code soon!
  • Maverick1st
    Maverick1st almost 12 years
    Very cool code. Simple to use and works perfectly for my purpose. Many thanks!!
  • Victor Engel
    Victor Engel over 11 years
    @Kazzar, On your first line did you really mean [CALayer layer] or did you mean [webView layer]?
  • FreeAsInBeer
    FreeAsInBeer about 11 years
    If you try using this on a view that doesn't clip subviews, then it won't work. You can toggle this in the "Attributes Inspector" tab of IB (it's called "Clip Subviews"), or set the property via code with view.clipsToBounds = YES;.
  • TPoschel
    TPoschel about 11 years
    The name of the variable is "leftBorder" but it looks like you are actually setting the right border with the code. I already gave it a +1 because I like the way it was solved any how.
  • pronebird
    pronebird almost 11 years
    The proper rectangle would be: { 0, 0, width, height }. What is the point in rendering offscreen at -1 position?
  • Krzysztof Romanowski
    Krzysztof Romanowski almost 11 years
    I think that frame code should be leftBorder.frame = CGRectMake(0, 0, 1, leftScrollView.frame.size.height);
  • MrTristan
    MrTristan about 10 years
    i'm glad at least one person here mentioned that this would be plopping the line on the left and not the right...
  • SeanR
    SeanR almost 10 years
    No, this draws a border on the right, but not on any other edges. However, you can adjust the offsets to get borders on more than one side. This is a neat way to save drawing multiple layers for multiple edges. Needs a bit more explanation to be clear what is actually happening, but this is a good solution.
  • Ramiro
    Ramiro over 8 years
    Consider using rightBorder.frame = CGRectMake(CGRectGetWidth(button.frame) - 1, 0, 1, CGRectGetHeight(button.frame)); if you need borderWidth > 1
  • Dave G
    Dave G over 8 years
    Just tried this and it resulted in a border but the width doesn't match the size of the button I added it to, the border is almost twice as long.
  • Itachi
    Itachi almost 7 years
    This answer is better than the above correct answer as it supports to auto-layout for views.
  • Doug Mead
    Doug Mead almost 7 years
    Upvoted this, but you could replace those C-style getters with properties now.. and use CGRect's init method
  • johndpope
    johndpope over 6 years
    you may want to switch self.layer.addSublayer(layer) to self.layer.insertSublayer(layer, at: UInt32(self.layer.sublayers?.count ?? 0))
  • Larry Lo
    Larry Lo over 6 years
    mine is still having right padding which I don't want this.
  • Chris Birch
    Chris Birch about 6 years
    Why go to the all that effort of working out those strange numbers when you're already using a shape layer? Just workout the path for the line, give that to the shape layer + no need for a layer mask
  • John Montgomery
    John Montgomery about 6 years
    Perfect, the accepted answer was giving me some issues that this one didn't have.