Introduction : pourquoi cette fichue ligne empêche-t-elle les développeurs de dormir ?
\n\nSi vous avez déjà essayé de concevoir une application « comme dans Apple Music » ou « comme dans Telegram », vous avez sûrement rencontré ce problème. Vous créez un UINavigationBar parfait avec un joli dégradé, une transparence ou une couleur personnalisée, vous lancez le simulateur — et vous voyez cette fine ligne grise ou noire (1 pixel) en bas. Elle ressemble à un artefact, à une saleté sur le verre. Et oui, elle énerve.
Cette ligne de 1px n'est pas un bug, c'est une fonctionnalité. C'est le shadowImage + backgroundImage qu'Apple a laissés par défaut pour une raison quelconque. Même sous iOS 17, elle apparaît encore si vous ne dites pas au système : « Hé, enlève ça ». La question sur Stack Overflow à ce sujet a recueilli des milliers de vues et des dizaines de réponses. Cela montre que le sujet est vraiment problématique.
\n\nDans cet article, je vais vous montrer 3 approches fonctionnelles en Swift pour masquer la ligne inférieure de UINavigationBar. Nous aborderons à la fois les anciennes méthodes (iOS 13-) et les méthodes modernes via UINavigationBarAppearance. C'est parti !
Méthode 1 : La classique — via backgroundImage et shadowImage
\n\nLa méthode la plus ancienne et la plus éprouvée. Elle fonctionne depuis iOS 5 (oui, depuis l'époque où le skeuomorphisme était à la mode). L'idée est simple : nous définissons une image vide comme fond et ombre.
\n\nÉtape 1 : Créer une image vide
\n\nextension UIImage {\n static func pixelImage(withColor color: UIColor = .clear) -> UIImage {\n let rect = CGRect(x: 0, y: 0, width: 1, height: 1)\n UIGraphicsBeginImageContext(rect.size)\n color.setFill()\n UIRectFill(rect)\n let image = UIGraphicsGetImageFromCurrentImageContext()\n UIGraphicsEndImageContext()\n return image ?? UIImage()\n }\n}\n\nÉtape 2 : Appliquer à navigationBar
\n\nfunc hideBottomLine() {\n let emptyImage = UIImage.pixelImage()\n navigationController?.navigationBar.setBackgroundImage(emptyImage, for: .default)\n navigationController?.navigationBar.shadowImage = emptyImage\n}\n\nAvantages : Fonctionne partout, même sur les anciennes versions d'iOS.
\nInconvénients : Ne fonctionne pas toujours correctement avec scrollEdgeAppearance et les grands titres. Si vous avez un UISearchBar, la ligne peut réapparaître.
Méthode 2 : La moderne — via UINavigationBarAppearance (iOS 13+)
\n\nDepuis iOS 13, Apple a introduit UINavigationBarAppearance. C'est un objet unique qui gère tous les états : standard, défilement et compact. Idéal pour ceux qui veulent « configurer une fois et oublier ».
Exemple complet pour UIViewController
\n\nfunc setupTransparentNavigationBar() {\n let appearance = UINavigationBarAppearance()\n appearance.configureWithTransparentBackground()\n appearance.backgroundColor = .clear\n appearance.shadowColor = .clear // supprime la ligne\n \n navigationController?.navigationBar.standardAppearance = appearance\n navigationController?.navigationBar.scrollEdgeAppearance = appearance\n navigationController?.navigationBar.compactAppearance = appearance\n}\n\nNotez bien : shadowColor = .clear est la ligne clé. Si vous ne l'écrivez pas, la ligne reste. configureWithTransparentBackground() rend le fond transparent, mais ne touche pas à l'ombre.
Si vous voulez un fond coloré, mais sans ligne :
\n\nlet appearance = UINavigationBarAppearance()\nappearance.configureWithOpaqueBackground()\nappearance.backgroundColor = .systemBlue\nappearance.shadowColor = .clear\n\nnavigationController?.navigationBar.standardAppearance = appearance\nnavigationController?.navigationBar.scrollEdgeAppearance = appearance\n\nAvantages : Code propre, facile à combiner avec les grands titres et la recherche.
\nInconvénients : iOS 13+ uniquement. Si le projet prend en charge iOS 12, il faudra