Is it possible to change the grey border-bottom color of the UINavigationBar in iOS7?
I already tried to remove to border, but this is not working:
[[UINavigationBar appearance] setShadowImage:[[UIImage alloc] init]];
Thanks!
Is it possible to change the grey border-bottom color of the UINavigationBar in iOS7?
I already tried to remove to border, but this is not working:
[[UINavigationBar appearance] setShadowImage:[[UIImage alloc] init]];
Thanks!
 
    
    You are removing the shadow but not the border, you need to do the following:
[[UINavigationBar appearance] setBackgroundImage:[[UIImage alloc] init] forBarMetrics:UIBarMetricsDefault];
[[UINavigationBar appearance] setShadowImage:[[UIImage alloc] init]];
To change the border use an image of 2 pixels width line:
[[UINavigationBar appearance] setShadowImage:[UIImage imageNamed:@"2pxWidthLineImage"]]; 
 
    
    Here is a category to change bottom color with height:
[self.navigationController.navigationBar setBottomBorderColor:[UIColor redColor] height:1];
Objective C:
UINavigationBar+Helper.h
#import <UIKit/UIKit.h>
@interface UINavigationBar (Helper)
- (void)setBottomBorderColor:(UIColor *)color height:(CGFloat)height;
@end
UINavigationBar+Helper.m
#import "UINavigationBar+Helper.h"
@implementation UINavigationBar (Helper)
- (void)setBottomBorderColor:(UIColor *)color height:(CGFloat)height {
    CGRect bottomBorderRect = CGRectMake(0, CGRectGetHeight(self.frame), CGRectGetWidth(self.frame), height);
    UIView *bottomBorder = [[UIView alloc] initWithFrame:bottomBorderRect];
    [bottomBorder setBackgroundColor:color];
    [self addSubview:bottomBorder];
}
@end
Swift:
extension UINavigationBar {
    func setBottomBorderColor(color: UIColor, height: CGFloat) {
        let bottomBorderRect = CGRect(x: 0, y: frame.height, width: frame.width, height: height)
        let bottomBorderView = UIView(frame: bottomBorderRect)
        bottomBorderView.backgroundColor = color
        addSubview(bottomBorderView)
    }
}
 
    
    Here is another way:
CALayer *border = [CALayer layer];
border.borderColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"border"]].CGColor;
border.borderWidth = 1;
CALayer *layer = self.navigationController.navigationBar.layer;
border.frame = CGRectMake(0, layer.bounds.size.height, layer.bounds.size.width, 1);
[layer addSublayer:border];
 
    
    The only way I found to change color is:
override func viewDidLoad() {
    super.viewDidLoad()
    if let navigationController = self.navigationController {
        let navigationBar = navigationController.navigationBar
        let navigationSeparator = UIView(frame: CGRectMake(0, navigationBar.frame.size.height - 1, navigationBar.frame.size.width, 0.5))
        navigationSeparator.backgroundColor = UIColor.redColor() // Here your custom color
        navigationSeparator.opaque = true
        self.navigationController?.navigationBar.addSubview(navigationSeparator)
    }
}
 
    
    I wrote an extension based on the other answers for easier usage in Swift:
extension UINavigationBar {
    func setBottomBorderColor(color: UIColor) {
        let navigationSeparator = UIView(frame: CGRectMake(0, self.frame.size.height - 0.5, self.frame.size.width, 0.5))
        navigationSeparator.backgroundColor = color
        navigationSeparator.opaque = true
        navigationSeparator.tag = 123
        if let oldView = self.viewWithTag(123) {
            oldView.removeFromSuperview()
        }
        self.addSubview(navigationSeparator)
    }
}
You can use this extension with calling the method in a context like that:
self.navigationController?.navigationBar.setBottomBorderColor(UIColor.whiteColor())
I found that pretty useful as I had to deal with that colored-border-problem.
 
    
    I solved this problem with the use of autolayouts. The solution works on different screen sizes and with orientation change.
extension UINavigationBar {
    @IBInspectable var bottomBorderColor: UIColor {
        get {
            return self.bottomBorderColor;
        }
        set {
            let bottomBorderRect = CGRect.zero;
            let bottomBorderView = UIView(frame: bottomBorderRect);
            bottomBorderView.backgroundColor = newValue;
            addSubview(bottomBorderView);
            bottomBorderView.translatesAutoresizingMaskIntoConstraints = false;
            self.addConstraint(NSLayoutConstraint(item: bottomBorderView, attribute: .trailing, relatedBy: .equal, toItem: self, attribute: .trailing, multiplier: 1, constant: 0));
            self.addConstraint(NSLayoutConstraint(item: bottomBorderView, attribute: .leading, relatedBy: .equal, toItem: self, attribute: .leading, multiplier: 1, constant: 0));
            self.addConstraint(NSLayoutConstraint(item: bottomBorderView, attribute: .top, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1, constant: 0));
            self.addConstraint(NSLayoutConstraint(item: bottomBorderView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute,multiplier: 1, constant: 1));
        }
    }
}
 
    
    Based on the answer from @sash I made an extension in Swift using Autolayout, explained right here.
In essence, the other solutions have the following pitfalls:
extension UINavigationBar {
  func setBottomBorderColor(color: UIColor, height: CGFloat) -> UIView {
    let bottomBorderView = UIView(frame: CGRectZero)
    bottomBorderView.translatesAutoresizingMaskIntoConstraints = false
    bottomBorderView.backgroundColor = color
    self.addSubview(bottomBorderView)
    let views = ["border": bottomBorderView]
    self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[border]|", options: [], metrics: nil, views: views))
    self.addConstraint(NSLayoutConstraint(item: bottomBorderView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: height))
    self.addConstraint(NSLayoutConstraint(item: bottomBorderView, attribute: .Bottom, relatedBy: .Equal, toItem: self, attribute: .Bottom, multiplier: 1.0, constant: height))    
    return bottomBorderView
  }
}
This let you still add a drop shadow if you need to, and this handles rotation nicely !
If you like simple and hacky solutions like I do, create a view that covers the default border:
UIView *navBarLineView = [[UIView alloc] initWithFrame:CGRectMake(0, CGRectGetHeight(self.navigationController.navigationBar.frame),
                                                                  CGRectGetWidth(self.navigationController.navigationBar.frame), 1)];
navBarLineView.backgroundColor = [UIColor redColor];
[self.navigationController.navigationBar addSubview:navBarLineView];
 
    
    budidino solutions works very well. Here it is for Swift:
let navBarLineView = UIView(frame: CGRectMake(0,
    CGRectGetHeight((navigationController?.navigationBar.frame)!),
    CGRectGetWidth((self.navigationController?.navigationBar.frame)!),
    1))
navBarLineView.backgroundColor = UIColor.whiteColor()
navigationController?.navigationBar.addSubview(navBarLineView)
 
    
    Well, if you want to remove bottom border you set shadow image to empty image
[navigationBar setShadowImage:[UIImage new]];
so if you want to set it to another color just create image with that color, I use a helper function to create image from color below (original source http://jslim.net/blog/2014/05/05/ios-customize-uitabbar-appearance/)
+ (UIImage *)imageFromColor:(UIColor *)color forSize:(CGSize)size 
{
return [UIImage imageFromColor:color forSize:size withCornerRadius:0];
}
+ (UIImage *)imageFromColor:(UIColor *)color forSize:(CGSize)size     withCornerRadius:(CGFloat)radius
{
CGRect rect = CGRectMake(0, 0, size.width, size.height);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, rect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// Begin a new image that will be the new image with the rounded corners
// (here with the size of an UIImageView)
UIGraphicsBeginImageContext(size);
// Add a clip before drawing anything, in the shape of an rounded rect
[[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:radius] addClip];
// Draw your image
[image drawInRect:rect];
// Get the image, here setting the UIImageView image
image = UIGraphicsGetImageFromCurrentImageContext();
// Lets forget about that we were drawing
UIGraphicsEndImageContext();
return image;
}
and in my navbar
[navigationBar setShadowImage:[UIImage imageFromColor:[UIColor redColor] forSize:CGSizeMake(CGRectGetWidth(self.tableView.frame), 1)]];
that's it, It's working for me, hope this help. Please consider changing the accepted answer because its not working and can be confusing
 
    
    To build on @sash's Swift implementation you can make the border responsive to rotation/trait changes by using constraints:
extension UINavigationBar {
  func setBottomBorderColor(color: UIColor, height: CGFloat) {
    let bottomBorderView = UIView()
    bottomBorderView.backgroundColor = color
    bottomBorderView.translatesAutoresizingMaskIntoConstraints = false
    addSubview(bottomBorderView)
    // Add constraints to make the bar always stay at the bottom of the nav bar and change size with rotation/trait changes
    let horizontalConstraint = NSLayoutConstraint(item: bottomBorderView, attribute: NSLayoutAttribute.centerX, relatedBy: NSLayoutRelation.equal, toItem: self, attribute: NSLayoutAttribute.centerX, multiplier: 1, constant: 0)
    let verticalConstraint = NSLayoutConstraint(item: bottomBorderView, attribute: NSLayoutAttribute.centerY, relatedBy: NSLayoutRelation.equal, toItem: self, attribute: NSLayoutAttribute.bottom, multiplier: 1, constant: 0)
    let widthConstraint = NSLayoutConstraint(item: bottomBorderView, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: self, attribute: .width, multiplier: 1, constant: 0)
    let heightConstraint = NSLayoutConstraint(item: bottomBorderView, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: height)
    self.addConstraints([horizontalConstraint, verticalConstraint, widthConstraint, heightConstraint])
  }
}
 
    
    Here's the method for creating image with clear color:
+ (UIImage*)imageFromColor:(UIColor *)color withSize:(CGSize)sizeImage
{
    UIImage *resultImage = nil;
    UIGraphicsBeginImageContext(sizeImage);
    CGContextSetFillColorWithColor(UIGraphicsGetCurrentContext(), color.CGColor);
    CGContextFillRect(UIGraphicsGetCurrentContext(), CGRectMake(0.0f, 0.0f, sizeImage.width, sizeImage.height));
    resultImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return resultImage;
}
Here's it's usage for removing annoying bottom line:
navigationBar.shadowImage = [UIImage imageFromColor:[UIColor clearColor] withSize:CGSizeMake(1.0f, 1.0f)];
 
    
    you can use Reveal to see the border color is the UIImageView's backgroundColor. so directly modifying the imageView's backgroundColor or hide it.
the code: i write in @interface QdtTabBarController : UITabBarController
Class backGroundClass = NSClassFromString(@"_UIBarBackground");
for (UIView *view in self.tabBar.subviews) {
    if ([view isKindOfClass:backGroundClass]) {
        for (UIView *view2 in view.subviews) {
            if ([view2 isKindOfClass:[UIImageView class]]) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    view2.backgroundColor = [UIColor redColor];
                });
            };
        };
        break;
    }
}
 
    
    I'm using RubyMotion with the RedPotion gem, which includes a StandardAppearance class. This is what I did!
Put this line at the top of your app_delegate.rb, just before the on_load method:
ApplicationStylesheet.new(nil).application_setup
Then, in your application_stylesheet.rb, put this as the last line in the application_setup method:
StandardAppearance.apply app.window
And then this is my StandardAppearance class:
class StandardAppearance
  def self.apply(window)
    Dispatch.once do
      UINavigationBar.appearance.tap do |o|
        o.setBackgroundImage(UIImage.alloc.init, forBarMetrics: UIBarMetricsDefault)
        o.shadowImage = UIImage.alloc.init
      end
    end
  end
end
 
    
    This will help you :)
[self.navigationController.navigationBar.layer setBorderWidth:2.0];// Just to make sure its working
[self.navigationController.navigationBar.layer setBorderColor:[[UIColor redColor] CGColor]];
