skip to Main Content

an image is worth a thousand word, please see the attached image. This is a mobile app that I am developing. There is visually that thin line between the navigation bar and search bar, but I have tried everything I can think of, as well as everything that ChatGPT suggested but I still can’t remove that line. Any out-of-the-box idea what I might be overlooking? How can I remove that thin line?

Thin line between navigation bar and search bar.

Edited: (Since some of you asked me of the codes, here they are, although as I said they are quite lengthy so I am not sure if that’s helpful…)

On AppDelegate (this method is called on each view controller under viewDidAppear):

extension UINavigationController{

func setupWhiteTintColor(){
    if #available(iOS 13.0, *) {
        let appearance = UINavigationBarAppearance()
        appearance.configureWithDefaultBackground()
        appearance.backgroundColor = UIColor(hex: "#4CAF50")
        appearance.shadowColor = UIColor.clear
        appearance.shadowImage = UIImage()
        appearance.titleTextAttributes = [NSAttributedString.Key.foregroundColor : UIColor.white,.font : UIFont.boldSystemFont(ofSize: 20)]
        navigationBar.standardAppearance = appearance;
        navigationBar.scrollEdgeAppearance = appearance;
        navigationBar.compactAppearance = appearance;
        navigationBar.tintColor = UIColor.white
        navigationBar.setGradientBackground(colors: [UIColor(hex: "#388E3C"), UIColor(hex: "#4CAF50")], startPoint: .topLeft, endPoint: .bottomRight)
    } else {
        self.navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor : UIColor.white,.font : UIFont.boldSystemFont(ofSize: 20)]
        self.navigationBar.tintColor = UIColor.white
        self.navigationBar.barTintColor = UIColor(hex: "#4CAF50")
        self.navigationBar.isTranslucent = false
        self.navigationBar.setBackgroundImage(UIImage(), for: .default)
        self.navigationBar.shadowImage = UIImage()
    }
}

}

class UINavigationBarGradientView: UIView {

enum Point {
    case topRight, topLeft
    case bottomRight, bottomLeft
    case custom(point: CGPoint)

    var point: CGPoint {
        switch self {
            case .topRight: return CGPoint(x: 1, y: 0)
            case .topLeft: return CGPoint(x: 0, y: 0)
            case .bottomRight: return CGPoint(x: 1, y: 1)
            case .bottomLeft: return CGPoint(x: 0, y: 1)
            case .custom(let point): return point
        }
    }
}

private weak var gradientLayer: CAGradientLayer!

convenience init(colors: [UIColor], startPoint: Point = .topLeft,
                 endPoint: Point = .bottomLeft, locations: [NSNumber] = [0, 1]) {
    self.init(frame: .zero)
    let gradientLayer = CAGradientLayer()
    gradientLayer.frame = frame
    layer.addSublayer(gradientLayer)
    self.gradientLayer = gradientLayer
    set(colors: colors, startPoint: startPoint, endPoint: endPoint, locations: locations)
    backgroundColor = .clear
}

func set(colors: [UIColor], startPoint: Point = .topLeft,
         endPoint: Point = .bottomLeft, locations: [NSNumber] = [0, 1]) {
    gradientLayer.colors = colors.map { $0.cgColor }
    gradientLayer.startPoint = startPoint.point
    gradientLayer.endPoint = endPoint.point
    gradientLayer.locations = locations
}

func setupConstraints() {
    guard let parentView = superview else { return }
    translatesAutoresizingMaskIntoConstraints = false
    topAnchor.constraint(equalTo: parentView.topAnchor).isActive = true
    leftAnchor.constraint(equalTo: parentView.leftAnchor).isActive = true
    parentView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
    parentView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
}

override func layoutSubviews() {
    super.layoutSubviews()
    guard let gradientLayer = gradientLayer else { return }
    gradientLayer.frame = frame
    superview?.addSubview(self)
}

}

extension UINavigationBar {
    func setGradientBackground(colors: [UIColor],
                               startPoint: UINavigationBarGradientView.Point = .topLeft,
                               endPoint: UINavigationBarGradientView.Point = .bottomLeft,
                               locations: [NSNumber] = [0, 1]) {
        guard let backgroundView = value(forKey: "backgroundView") as? UIView else { return }
        guard let gradientView = backgroundView.subviews.first(where: { $0 is UINavigationBarGradientView }) as? UINavigationBarGradientView else {
            let gradientView = UINavigationBarGradientView(colors: colors, startPoint: startPoint,
                                                           endPoint: endPoint, locations: locations)
            backgroundView.addSubview(gradientView)
            gradientView.setupConstraints()
            return
        }
        gradientView.set(colors: colors, startPoint: startPoint, endPoint: endPoint, locations: locations)
    }
}

extension UITabBar {
    func setGradientBackground(colors: [UIColor],
                               startPoint: UINavigationBarGradientView.Point = .topLeft,
                               endPoint: UINavigationBarGradientView.Point = .bottomLeft,
                               locations: [NSNumber] = [0, 1]) {
        guard let backgroundView = value(forKey: "backgroundView") as? UIView else { return }
        guard let gradientView = backgroundView.subviews.first(where: { $0 is UINavigationBarGradientView }) as? UINavigationBarGradientView else {
            let gradientView = UINavigationBarGradientView(colors: colors, startPoint: startPoint,
                                                           endPoint: endPoint, locations: locations)
            backgroundView.addSubview(gradientView)
            gradientView.setupConstraints()
            return
        }
        gradientView.set(colors: colors, startPoint: startPoint, endPoint: endPoint, locations: locations)
    }
}

On each View Controller the following function is run:

func setupNavigationBarTitleView() {
    let imageView = UIImageView(image: UIImage(named: "TransparentToyzone"))
    imageView.contentMode = .scaleAspectFit
    
    // Set the height constraint to 30 pixels
    imageView.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([
        imageView.heightAnchor.constraint(equalToConstant: 30)
    ])
    
    // Set the image view as the title view of the navigation bar
    self.navigationItem.titleView = imageView
}

2

Answers


  1. Chosen as BEST ANSWER

    It turns out that the visual border comes from search bar instead, and for some reasons setting searchbar.layer.borderWidth = 0 does not help. however, by setting searchbar.layer.borderWidth = 1 and then also set the borderColor to be the same color as navigation bar and search bar, the border effectively disappear.


  2. You will need to set the bar’s appearance using an instance of UINavigationBarAppearance. Specifically, you will want to set the shadowColor attribute to nil or .clear.

    override func viewDidLoad() {
      super.viewDidLoad()
      let appearance = UINavigationBarAppearance()
      appearance.shadowColor = .clear
      navigationController?.navigationBar.scrollEdgeAppearance = appearance
    }
    

    There are other appearance properties on UINavigationBar that may apply depending on location of the navigation bar on the screen.

    If you want to set this automatically for all navigation bars, do this early in your app launch

    let appearance = UINavigationBarAppearance()
    appearance.shadowColor = .clear
    UINavigationBar.appearance().scrollEdgeAppearance = appearance
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search