barra di navigazione bug del pulsante immagine barra di destra iOS 11


101

Questo codice funziona bene in ios10. ottengo la mia etichetta e un pulsante immagine che è il profilo della foto dell'utente, circolare rotondo .. ok. ma quando si esegue il simulatore xcode 9 ios11 lo ottengo allungato. la cornice del pulsante deve essere 32x32, quando si controlla la sim e si ottiene la vista e si dice a xcode di descrivere la vista, ottengo l'output come 170x32 o qualcosa del genere.

ecco il mio codice.

let labelbutton = UIButton( type: .system)
    labelbutton.addTarget(self, action:#selector(self.toLogin(_:)), for: .touchUpInside)
    labelbutton.setTitleColor(UIColor.white, for: .normal)
    labelbutton.contentHorizontalAlignment = .right
    labelbutton.titleLabel?.font = UIFont.systemFont(ofSize: 18.00)



    let button = UIButton(type: .custom)
     button.addTarget(self, action:#selector(self.toLogin(_:)), for: .touchUpInside)
     button.frame = CGRect(x: 0, y: 0, width: 32, height: 32)
     button.setTitleColor(UIColor.white, for: .normal)
     button.setTitleColor(UIColor.white, for: .highlighted)


    var buttomItem : UIBarButtonItem = UIBarButtonItem()
    buttomItem.customView = button
    buttomItem.target = self
    buttomItem.action = "ToLogin"

    var labelItem : UIBarButtonItem = UIBarButtonItem()
    labelItem.customView = labelbutton
    labelItem.target = self
    labelItem.action = "ToLogin"


    if let user = PFUser.current() {
        print("LOGIN : checkiando si existe usuario ")
            labelbutton.setTitle(USERNAME, for: UIControlState.normal)
            labelbutton.sizeToFit()

        if(user["profile_photo_url"] != nil) {
            print(" ENCONTRO PROFILE PHOTO URL NOT NIL Y ES \(user["profile_photo_url"])")
            let photoURL = user["profile_photo_url"] as! String
            let a = LoginService.sharedInstance
            a.downloadImage(url: photoURL, complete: { (complete) in

                if (complete) {

                    button.setImage(LoginService.sharedInstance.profile_photo! , for: UIControlState.normal)

                    button.layer.cornerRadius = 0.5 * button.bounds.size.width
                   // button.imageView!.contentMode = .scaleAspectFit
                   // button.imageView!.frame = CGRect(x: 0, y: 0, width: 40, height: 40)
                    //button.imageView!.contentMode = .scaleAspectFit
                    //button.imageView!.clipsToBounds = true
                    //button.imageView!.layer.cornerRadius = 60
                    button.clipsToBounds = true
                    self.NavigationItem.rightBarButtonItems = [buttomItem,labelItem]
                }


            })
        } else {
                self.NavigationItem.rightBarButtonItem = labelItem

        }
            print(" EL FRAME DEL BUTTON ES \(button.frame)")

    } else {

        labelbutton.setTitle("Login", for: UIControlState.normal)
        labelbutton.sizeToFit()
        self.NavigationItem.rightBarButtonItem = labelItem

    }

inserisci qui la descrizione dell'immagine


Hai utilizzato la visualizzazione stack nella barra di navigazione?
Vlad Khambir

@ V.Khambir Nop ...: /
lorenzo gonzalez

questa segnalazione di bug è da qualche parte?
Edu

iOS 11 utilizza AutoLayout per il layout degli elementi di navigazione. Nel caso in cui sia necessario spostare l' UIButtoninterno UIBarButtonItem, utilizzarebutton.imageEdgeInsets = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: -20)
onmyway133

Risposte:


188

Motivo

Il problema si presenta perché da ios 11 UIBarButtonItemutilizza l'autolayout invece di occuparsi dei frame.

Soluzione

Dovresti aggiungere un vincolo di larghezza per questo pulsante immagine se usi Xcode 9.

 button.widthAnchor.constraint(equalToConstant: 32.0).isActive = true
 button.heightAnchor.constraint(equalToConstant: 32.0).isActive = true

PS

buttonnon è UIBarButtonItem, è UIButtondentro UIBarButtonItem. Dovresti impostare il vincolo non per UIBarButtonItem, ma per gli elementi al suo interno.


3
@ V.Khambir ora ricevo questo problema. Ma con questa stessa soluzione con xcode 9, e se corro nel dispositivo ios 1 va bene .. Ma se corro nel dispositivo versione ios 10 .. le immagini dei pulsanti della barra non vengono visualizzate affatto. Come posso risolvere per tutte le versioni per questo. Ho controllato il dispositivo di entrambi ios 11, ios 10. Risultati buoni solo nella versione ios 1. in iOS 10, l'immagine non viene visualizzata affatto
David

@spikesa, dovrebbe funzionare su entrambe le versioni di iOS, probabilmente hai impostato vincoli errati.
Vlad Khambir

@ V.Khambir Il valore di tipo 'UIBarButtonItem' non ha membri 'widthAnchor' in Xcode 9 all'interno di un condizionale if #available (iOS 11.0, *)?
Ryan Brodie

1
@jped hai trovato una soluzione per questo? Non funziona anche per me su iOS 10 con Xcode 9
swalkner

1
Grande. Devo amare questi cambiamenti decisivi. Apple ha documentato un elenco di questi tipi di modifiche su una pagina o sulle note di rilascio da qualche parte?
GONeale

53

Grazie a tutti per aver contribuito! avete ragione ragazzi !. per xcode9 ios11 devi mettere un vincolo.

 let widthConstraint = button.widthAnchor.constraint(equalToConstant: 32)
 let heightConstraint = button.heightAnchor.constraint(equalToConstant: 32)
 heightConstraint.isActive = true
 widthConstraint.isActive = true

1
Questo ha funzionato anche per me, ma qualcuno può spiegare perché è necessario per iOS 11 quando non lo era mai stato prima?
stonedauwg

9
UINavigationBar ora impagina le sue viste secondarie utilizzando layout automatico
mangerlahn

2
Non commettere lo stesso errore che ho fatto: ho spento translatesAutoresizingMaskIntoConstraintse poi ho scoperto che iOS 9 era completamente rotto (ma sembrava a posto su iOS 10 e 11)
xaphod

2
Value of type 'UIBarButtonItem' has no member 'widthAnchor'in Xcode 9 all'interno di un if #available(iOS 11.0, *)condizionale?
Ryan Brodie

@ lorenzo-gonzalez Come hai fatto a farcela? Sono bloccato su questo.
Alessandro Lucarini

18

Il codice Objective C è obsoleto ora. Ma per l'utente che deve creare / mantenere progetti Objective C in iOS 11 è utile la seguente traduzione da Swift (risposta di Karoly Nyisztor) a Objective C.

//  UIView+Navbar.h

#import <UIKit/UIKit.h>

@interface UIView (Navbar)

- (void)applyNavBarConstraints:(CGFloat)width height:(CGFloat)height;

@end

//----------

//  UIView+Navbar.m

#import "UIView+Navbar.h"

@implementation UIView (Navbar)

- (void)applyNavBarConstraints:(CGFloat)width height:(CGFloat)height
{
    if (width == 0 || height == 0) {
        return;
    }

    NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:height];
    NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:width];
    [heightConstraint setActive:TRUE];
    [widthConstraint setActive:TRUE];
}

//----------

// Usage :-
[button applyNavBarConstraints:33 height:33];

Freddo. In realtà, avevo bisogno anche della versione Objective-C. A proposito, Xcode 9 continua a ridimensionare casualmente gli elementi della barra di navigazione nello storyboard. Devo ricontrollare ogni volta prima di inviare le mie modifiche. Spero che questo venga risolto presto.
Karoly Nyisztor,

sei il mio eroe, perché ho bisogno di refactoring del vecchio progetto con obiettivo-c.
Marosdee Uma

18

Bene, il nuovo barButtonItemusa il layout automatico invece di occuparsi dei frame.

L'immagine che stavi aggiungendo al pulsante è più grande delle dimensioni del pulsante stesso. Ecco perché il pulsante stesso è stato allungato alla dimensione dell'immagine. Devi ridimensionare l'immagine in modo che corrisponda alla dimensione del pulsante necessario, prima di aggiungerla al pulsante.


14

Ho scritto una piccola estensione per impostare i vincoli sugli elementi della barra di navigazione:

import UIKit

extension UIView {
    func applyNavBarConstraints(size: (width: CGFloat, height: CGFloat)) {
    let widthConstraint = self.widthAnchor.constraint(equalToConstant: size.width)
    let heightConstraint = self.heightAnchor.constraint(equalToConstant: size.height)
    heightConstraint.isActive = true
    widthConstraint.isActive = true
  }
}

// Usage
button.applyNavBarConstraints(size: (width: 33, height: 33))

Grande idea! Applicato questo UIButtonfunziona molto bene.
Alessandro Ornano

12

L'ho fatto in obiettivo usando le seguenti righe:

NSLayoutConstraint * widthConstraint = [customButton.widthAnchor constraintEqualToConstant:40];
NSLayoutConstraint * HeightConstraint =[customButton.heightAnchor constraintEqualToConstant:40];
[widthConstraint setActive:YES];
[HeightConstraint setActive:YES];

UIBarButtonItem* customBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:customButton];
self.navigationItem.leftBarButtonItem = customBarButtonItem;

Grazie Buona programmazione !!


7

Cosa ho fatto?

Nella mia app, ho aggiunto l'immagine del profilo su navigationBar alla voce rightBarButton. prima di iOS 11 funzionava bene e veniva visualizzato correttamente, ma una volta aggiornato a iOS 11, cambia il comportamento come un colpo

inserisci qui la descrizione dell'immagine

Quindi ho aggiunto l' UIViewelemento del pulsante destro e impostato UIButtoncome sottoview di UIView? Come sotto,

inserisci qui la descrizione dell'immagine

E ho impostato i vincoli di altezza e larghezza di UIButton.

inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine

E il mio problema è risolto. Non dimenticare di impostare UIViewil colore di sfondo di come colore chiaro .

NOTA: Se il tuo pulsante non funziona, controlla che la tua UIView'saltezza sia 0 qui dovresti cambiare l'altezza da 0 a 44 o quello che vuoi. E fallo clipToBound = true, ora puoi impostare la posizione del tuo pulsante e funzionerà bene.


Funziona, tuttavia il pulsante smette di funzionare quando lo aggiungi in una vista. Qualche consiglio?
eonista

@GitSync Controlla l'altezza della tua vista sarà 0 cambiarla in 44 o quello che vuoi e fare clipToBound = true e quindi impostare il pulsante.
iPatel

1
Wow. lavori!
Suggerimento

è necessaria la visualizzazione del contenitore? Non posso semplicemente usare UIButton direttamente?
igrek

5

La modifica di widthAnchor/ heightAnchorfunzionerà solo su dispositivi iOS 11+. Per i dispositivi iOS 10 devi seguire il modo classico di cambiare manualmente i frame. Il fatto è che nessuno dei due approcci funziona per entrambe le versioni, quindi è assolutamente necessario alternare in modo programmatico a seconda della versione di runtime, come di seguito:

if #available(iOS 11.0, *)
{
   button.widthAnchor.constraint(equalToConstant: 32.0).isActive = true
   button.heightAnchor.constraint(equalToConstant: 32.0).isActive = true
}else
{
   var frame = button.frame
   frame.size.width = 32.0
   frame.size.height = 32.0
   button.frame = frame
}

1
Grazie per il suggerimento su iOS 10! Avevo la correzione di iOS 11 funzionante ma non riuscivo a capirlo per iOS 10.
Clifton Labrum

3

Anche se iOS 11 utilizza il layout automatico per la barra di navigazione, è possibile farlo funzionare tradizionalmente impostando i frame. Ecco il mio codice che funziona per ios11 e ios10 o versioni precedenti:

func barItemWithView(view: UIView, rect: CGRect) -> UIBarButtonItem {
    let container = UIView(frame: rect)
    container.addSubview(view)
    view.frame = rect
    return UIBarButtonItem(customView: container)
}

ed ecco come è composto l'elemento bar:

    let btn = UIButton()
    btn.setImage(image.withRenderingMode(.alwaysTemplate), for: .normal)
    btn.tintColor = tint
    btn.imageView?.contentMode = .scaleAspectFit
    let barItem = barItemWithView(view: btn, rect: CGRect(x: 0, y: 0, width: 22, height: 22))
    return barItem

3

L'imposizione di vincoli a livello di codice ha funzionato per me per gli utenti che eseguono iOS 11.X. Tuttavia, il pulsante della barra era ancora allungato per gli utenti che eseguivano iOS 10.X. Immagino che i revisori di AppStore eseguissero iOS 11.X, quindi non sono riusciti a identificare il mio problema, quindi la mia app è stata pronta per la vendita e caricata ..

La mia soluzione era semplicemente cambiare le dimensioni della mia immagine a 30x30 in un altro software (la dimensione dell'immagine precedente era 120x120).


1
Poiché la barra di navigazione in ios10 si ridimensiona automaticamente e ios11 è il layout automatico, è necessario gestire con if #available (iOS 11, *) {}
Paulo Sigales

Stavo
esaminando

Ottima, semplice risposta. Grazie. Nient'altro funzionava e mi stava facendo impazzire.
Bretagna

0

Ho anche avuto successo implementando la intrinsicContentSizerestituzione di una dimensione appropriata per qualsiasi sottoclasse UIView personalizzata che intendo utilizzare come customView.


0

Ho creato un elemento pulsante della barra e poi l'ho aggiunto alla barra di navigazione.

    private var addItem: UIBarButtonItem = {
        let addImage = UIImage(named: "add")
        let addButton = UIButton(type: UIButton.ButtonType.custom)
        addButton.setBackgroundImage(addImage, for: UIControl.State())
        addButton.frame = CGRect(x: 0, y: 0, width: (addImage?.size.width)!, height: (addImage?.size.height)!)
        let addItem = UIBarButtonItem(customView: addButton)
        return addItem
    }()

 private var contactsItem: UIBarButtonItem = {
        let contactsImage = UIImage(named: "contacts")
        let contactsButton = UIButton(type: UIButton.ButtonType.custom)
        contactsButton.setBackgroundImage(contactsImage, for: UIControl.State())
        contactsButton.frame = CGRect(x: 0, y: 0, width: (contactsImage?.size.width)!, height: (contactsImage?.size.height)!)
        let contactsItem = UIBarButtonItem(customView: contactsButton)
        return contactsItem
    }()

In viewDidLoad ()

let spacerBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.fixedSpace, target: nil, action: nil)
        spacerBarButtonItem.width = 11
        navigationItem.rightBarButtonItems = [addItem, spacerBarButtonItem, contactsItem]

Qui ho l'immagine di 28x28.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.