web-dev-qa-db-de.com

benutzerdefiniertes Hintergrundbild mit großer Titel-Navigationsleiste in iOS 11

Wie stellen Sie in iOS 11 ein benutzerdefiniertes Hintergrundbild für die große Navigationsleiste ein? Ich verwende eine benutzerdefinierte Unterklasse, die ich den navigationControllers im Storyboard zugewiesen habe.

So erstelle ich meine benutzerdefinierte NavBar:

class CustomNavigationController: UINavigationController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        self.navigationBar.tintColor = UIColor(red:1, green:1, blue:1, alpha:0.6)
        self.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.white]
        if #available(iOS 11.0, *) {
            self.navigationBar.prefersLargeTitles = true
            self.navigationItem.largeTitleDisplayMode = .automatic
            self.navigationBar.largeTitleTextAttributes = [NSForegroundColorAttributeName: UIColor.white]
            self.navigationBar.barTintColor = UIColor.green
        }
        self.navigationBar.isTranslucent = false
        self.navigationBar.setBackgroundImage(#imageLiteral(resourceName: "navigationBarBackground"), for: .default)
        self.navigationBar.shadowImage = #imageLiteral(resourceName: "navigationBarShadow")
    }
}

Seltsamerweise funktioniert die setBackgroundImage(image, for: .default) nicht für die großen Titel. Hat es vorher mit iOS 10 funktioniert und auch wenn ich das iPhone drehe (und die kleine NavBar aktiviere), ist der Hintergrund wieder da?

Edit: Die backgroundImage wird noch gerendert, aber irgendwie verborgen. Nur wenn Sie mit dem Scrollen beginnen und die "normale" Navigationsleiste angezeigt wird, ist das backgroundImage sichtbar. Auch das barTintColor wird in diesem Fall komplett ignoriert .  screenshot  GIF

18
alexkaessner

Ich hatte das gleiche Problem, das durch behoben wurde

Entfernen Sie setBackgroundImage und verwenden Sie die BarTint-Farbe für das Musterbild

let bgimage = imageWithGradient(startColor: UIColor.red, endColor: UIColor.yellow, size: CGSize(width: UIScreen.main.bounds.size.width, height: 1))
self.navigationBar.barTintColor = UIColor(patternImage: bgimage!)

Holen Sie sich ein Bild mit Farbverläufen

func imageWithGradient(startColor:UIColor, endColor:UIColor, size:CGSize, horizontally:Bool = true) -> UIImage? {

    let gradientLayer = CAGradientLayer()
    gradientLayer.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height)
    gradientLayer.colors = [startColor.cgColor, endColor.cgColor]
    if horizontally {
        gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
        gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
    } else {
        gradientLayer.startPoint = CGPoint(x: 0.5, y: 0.0)
        gradientLayer.endPoint = CGPoint(x: 0.5, y: 1.0)
    }

    UIGraphicsBeginImageContext(gradientLayer.bounds.size)
    gradientLayer.render(in: UIGraphicsGetCurrentContext()!)
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return image
}
15
oldrinmendez

In iOS 11 müssen Sie kein Hintergrundbild mehr setzen (Remove deklarieren), wenn Sie große Titel verwenden. Stattdessen müssen Sie BarTintColor verwenden.

class CustomNavigationController: UINavigationController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        self.navigationBar.tintColor = UIColor(red:1, green:1, blue:1, alpha:0.6)
        self.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.white]
        if #available(iOS 11.0, *) {
            self.navigationBar.prefersLargeTitles = true
            self.navigationItem.largeTitleDisplayMode = .automatic
            self.navigationBar.largeTitleTextAttributes = [NSForegroundColorAttributeName: UIColor.white]
            self.navigationBar.barTintColor = UIColor(red:1, green:1, blue:1, alpha:1)
        }
        else {
            self.navigationBar.setBackgroundImage(#imageLiteral(resourceName: "navigationBarBackground"), for: .default)                
        }
        self.navigationBar.shadowImage = #imageLiteral(resourceName: "navigationBarShadow")
        self.navigationBar.isTranslucent = false
    }
}
4
Pocheshire

Versuchen Sie diesen Code (Swift 4.0):

in viewDidLoad ()

self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.black]
if #available(iOS 11.0, *) {
    self.navigationController?.navigationBar.prefersLargeTitles = true
    self.navigationItem.largeTitleDisplayMode = .automatic
    self.navigationController?.navigationBar.largeTitleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.black]
} else {
    //iOS <11.0
}
self.title = "Title"
self.navigationController?.navigationBar.barTintColor = UIColor(patternImage: #imageLiteral(resourceName: "nav_bg"))
self.navigationController?.navigationBar.isTranslucent = false
2
TomikeKrasnay

In Xamarin wäre es so:

this.NavigationBar.BackgroundColor = UIColor.Clear;

      var gradientLayer = new CAGradientLayer
      {
        Frame = new CGRect(0, 0, UIApplication.SharedApplication.StatusBarFrame.Width,
              UIApplication.SharedApplication.StatusBarFrame.Height + this.NavigationBar.Frame.Height),
        Colors = new CGColor[]
              {Constants.Defaults.Navigation.RealBlueColor.ToCGColor(), Constants.Defaults.Navigation.RealBlueColor.ToCGColor()}
      };

      UIGraphics.BeginImageContext(gradientLayer.Bounds.Size);
      gradientLayer.RenderInContext((UIGraphics.GetCurrentContext()));
      UIImage image = UIGraphics.GetImageFromCurrentImageContext();
      UIGraphics.EndImageContext();

      this.View.Layer.InsertSublayer(gradientLayer, 0);
      this.NavigationBar.BarTintColor = UIColor.FromPatternImage(image);

Das this.View.Layer.Insert ist optional. Ich brauche es, wenn ich ein Bild auf der Navigationsleiste auf und ab rolle 

1
gorhal

Das Ändern der Taktart hat für mich nicht funktioniert, also ändere ich die Ebene in der Navigationsleiste

 navigationBar.layer.backgroundColor = UIColor(patternImage:
        UIImage(named: "BG-Roof1")!.resizableImage(withCapInsets:
            UIEdgeInsets(top: 0, left: 0, bottom: 10, right: 0), resizingMode: .stretch)).cgColor
0
user3736373

Huckepack auf die Antwort von oldrinmendez - diese Lösung eignet sich perfekt für einen horizontalen Farbverlauf.

Für einen VERTICAL-Farbverlauf konnte ich dieselbe Funktion aus der Antwort von oldrinmendez verwenden, indem ich ihn erneut in scrollViewDidScroll aufrief. Dadurch wird die Höhe des Verlaufsbildes beim Scrollen des Benutzers kontinuierlich angepasst.

Beginne mit der Funktion von oldrinmendez:

func imageWithGradient(startColor:UIColor, endColor:UIColor, size:CGSize, horizontally:Bool) -> UIImage? {

        let gradientLayer = CAGradientLayer()
        gradientLayer.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height)
        gradientLayer.colors = [startColor.cgColor, endColor.cgColor]
        if horizontally {
            gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
            gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
        } else {
            gradientLayer.startPoint = CGPoint(x: 0.5, y: 0)
            gradientLayer.endPoint = CGPoint(x: 0.5, y: 1)
        }

        UIGraphicsBeginImageContext(gradientLayer.bounds.size)
        gradientLayer.render(in: UIGraphicsGetCurrentContext()!)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }

Erstellen Sie eine Aktualisierungsfunktion, um sie mit den gewünschten Optionen aufzurufen:

func updateImageWithGradient() {

        let navBarHeight  = self.navigationController?.navigationBar.frame.size.height
        let statusBarHeight = UIApplication.shared.statusBarFrame.height
        let heightAdjustment: CGFloat = 2

        let gradientHeight = navBarHeight! + statusBarHeight + heightAdjustment

        let bgimage = imageWithGradient(startColor: UIColor.red, endColor: UIColor.orange, size: CGSize(width: UIScreen.main.bounds.size.width, height: gradientHeight), horizontally: false)
        navigationController?.navigationBar.barTintColor = UIColor(patternImage: bgimage!)
    }

Schließlich fügen Sie die Aktualisierungsfunktion zu scrollViewDidScroll & ViewDidApper hinzu: ViewDidAppear verwenden, damit die korrekte Navigationsleistenhöhe zurückgegeben wird

override func viewDidAppear(_ animated: Bool) {
        updateImageWithGradient()
    }

override func scrollViewDidScroll(_ scrollView: UIScrollView) {
     DispatchQueue.main.async {
        updateImageWithGradient()
       }
    }
0
iOS_Mouse