更改导航栏底部边框颜色Swift

28

它可以与

import UIKit

class ViewController: UIViewController {

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    self.navigationController?.navigationBar.setBackgroundImage(UIImage(), forBarMetrics: .Default)
    self.navigationController?.navigationBar.shadowImage = UIColor.redColor().as1ptImage()


}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}


}

extension UIColor {
    func as1ptImage() -> UIImage {
        UIGraphicsBeginImageContext(CGSizeMake(1, 1))
        let ctx = UIGraphicsGetCurrentContext()
        self.setFill()
        CGContextFillRect(ctx, CGRect(x: 0, y: 0, width: 1, height: 1))
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }
}

但是当我添加一个UITableView时,它并没有出现,当我添加一个UISearchView时,它出现了,但是移除了导航栏。

有人知道如何解决这个问题吗?

8个回答

46

你需要调整导航栏的 shadowImage 属性。

尝试以下代码。我创建了一个 UIColor 的分类作为辅助函数,但你可以按照自己的喜好进行重构。

extension UIColor {
    func as1ptImage() -> UIImage {
        UIGraphicsBeginImageContext(CGSizeMake(1, 1))
        let ctx = UIGraphicsGetCurrentContext()
        self.setFill()
        CGContextFillRect(ctx, CGRect(x: 0, y: 0, width: 1, height: 1))
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }
}

选项1:在单个导航栏上

然后在您的视图控制器中(将UIColor更改为您喜欢的颜色):

// We can use a 1px image with the color we want for the shadow image
self.navigationController?.navigationBar.shadowImage = UIColor.redColor().as1ptImage()

// We need to replace the navigation bar's background image as well 
// in order to make the shadowImage appear. We use the same 1px color tecnique
self.navigationController?.navigationBar.setBackgroundImage(UIColor.yellowColor‌​().as1ptImage(), forBarMetrics: .Default)    

选项2:使用外观代理在所有导航栏上

不需要在每个导航栏上设置背景图像和阴影图像,可以依靠UIAppearance代理。您可以尝试将这些行添加到您的AppDelegate中,而不是在viewDidLoad中添加先前的行。

// We can use a 1px image with the color we want for the shadow image
UINavigationBar.appearance().shadowImage = UIColor.redColor().as1ptImage()

// We need to replace the navigation bar's background image as well 
// in order to make the shadowImage appear. We use the same 1px color technique
UINavigationBar.appearance().setBackgroundImage(UIColor.yellowColor().as1ptImage(), forBarMetrics: .Default)

谢谢,我应该把UIColor扩展放在哪里? - TheoF
是的,你不能把*放在类里面。它起作用了吗? - Alessandro Orrù
是的,两者都是我用于先前代码的UIViewController的子视图。 - TheoF
关于导航栏颜色丢失的问题,可能是因为我们正在更换背景图片,所以它变成了透明。你应该使用这个:self.navigationController?.navigationBar.setBackgroundImage(UIColor.yellowColor().as1ptImage(), forBarMetrics: .Default),使用你想要的颜色。无论如何,我仍然不理解"不出现在tableview上"的问题。它出现在导航栏上,而不是特定的视图上。我真的需要看到代码或一些截图。 - Alessandro Orrù
我的错误,我有一个UIViewController、一个UISearchView和一个UITableView... 这是3个不同的屏幕,现在我明白为什么不清楚了... 是我语言上的错误。 - TheoF
显示剩余16条评论

24

感谢@TheoF、@Alessandro和@Pavel做出的出色贡献。

以下是我为...所做的内容:

Swift 4

extension UIColor {

    /// Converts this `UIColor` instance to a 1x1 `UIImage` instance and returns it.
    ///
    /// - Returns: `self` as a 1x1 `UIImage`.
    func as1ptImage() -> UIImage {
        UIGraphicsBeginImageContext(CGSize(width: 1, height: 1))
        setFill()
        UIGraphicsGetCurrentContext()?.fill(CGRect(x: 0, y: 0, width: 1, height: 1))
        let image = UIGraphicsGetImageFromCurrentImageContext() ?? UIImage()
        UIGraphicsEndImageContext()
        return image
    }
}

viewDidLoad() 中使用它:

/* In this example, I have a ViewController embedded in a NavigationController in IB. */

// Remove the background color.
navigationController?.navigationBar.setBackgroundImage(UIColor.clear.as1ptImage(), for: .default)

// Set the shadow color.
navigationController?.navigationBar.shadowImage = UIColor.gray.as1ptImage()

5

Swift 4.0 - 5.2 解决方案

以下是一个小扩展,可以更改底部导航栏线的高度和颜色。

extension UINavigationController
{
    func addCustomBottomLine(color:UIColor,height:Double)
    {
        //Hiding Default Line and Shadow
        navigationBar.setValue(true, forKey: "hidesShadow")
    
        //Creating New line
        let lineView = UIView(frame: CGRect(x: 0, y: 0, width:0, height: height))
        lineView.backgroundColor = color
        navigationBar.addSubview(lineView)
    
        lineView.translatesAutoresizingMaskIntoConstraints = false
        lineView.widthAnchor.constraint(equalTo: navigationBar.widthAnchor).isActive = true
        lineView.heightAnchor.constraint(equalToConstant: CGFloat(height)).isActive = true
        lineView.centerXAnchor.constraint(equalTo: navigationBar.centerXAnchor).isActive = true
        lineView.topAnchor.constraint(equalTo: navigationBar.bottomAnchor).isActive = true
    }
}

在添加此扩展后,您可以在任何 UINavigationController 上调用此方法(例如从 ViewController 的 viewDidLoad())。
self.navigationController?.addCustomBottomLine(color: UIColor.black, height: 20)

4
将 @alessandro-orru 的答案整合到一个扩展中
extension UINavigationController {

    func setNavigationBarBorderColor(_ color:UIColor) {
        self.navigationBar.shadowImage = color.as1ptImage()
    }
}

extension UIColor {

    /// Converts this `UIColor` instance to a 1x1 `UIImage` instance and returns it.
    ///
    /// - Returns: `self` as a 1x1 `UIImage`.
    func as1ptImage() -> UIImage {
        UIGraphicsBeginImageContext(CGSize(width: 1, height: 1))
        setFill()
        UIGraphicsGetCurrentContext()?.fill(CGRect(x: 0, y: 0, width: 1, height: 1))
        let image = UIGraphicsGetImageFromCurrentImageContext() ?? UIImage()
        UIGraphicsEndImageContext()
        return image
    }
}

然后在您的视图控制器中添加以下代码:

self.navigationController?.setNavigationBarBorderColor(UIColor.red)

我更喜欢这个答案!简洁易懂,适用于Swift 4+。 - MillerMedia

4
从iOS 13开始,您可以使用UINavigationBarAppearance()类和shadowColor属性进行设置:
if #available(iOS 13.0, *) {
  let style = UINavigationBarAppearance()
  style.shadowColor = UIColor.clear // Effectively removes the border
  navigationController?.navigationBar.standardAppearance = style

  // Optional info for follow-ups:
  // The above will override other navigation bar properties so you may have to assign them here, for example:
  //style.buttonAppearance.normal.titleTextAttributes = [.font: UIFont(name: "YourFontName", size: 17)!]
  //style.backgroundColor = UIColor.orange
  //style.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white,
                               NSAttributedString.Key.font: UIFont(name: "AnotherFontName", size: 20.0)!]
} else {
  // Fallback on earlier versions
}

2

iOS 13及以上版本

    guard let navigationBar = navigationController?.navigationBar else { return }
    navigationBar.isTranslucent = true
    if #available(iOS 13.0, *) {
        let appearance = UINavigationBarAppearance()
        appearance.configureWithTransparentBackground()
        appearance.backgroundImage = UIImage()
        appearance.backgroundColor = .clear
        navigationBar.standardAppearance = appearance
    } else {
        navigationBar.setBackgroundImage(UIImage(), for: .default)
        navigationBar.shadowImage = UIImage()
    }

1

现在有更好的选择:

UINavigationBar.appearance().shadowImage = UIImage()

1

对于 Swift 3.0,只需更改此行:

CGContextFillRect(ctx, CGRect(x: 0, y: 0, width: 1, height: 1))

to this:

ctx?.fill(CGRect(x: 0, y: 0, width: 1, height: 1))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接