barre de navigation rightbaritem bug du bouton d'image iOS 11

101

Ce code fonctionne correctement dans ios10. j'obtiens mon étiquette et un bouton d'image qui est le profil de photo d'utilisateur, rond circulaire .. ok. mais lors de l'exécution du simulateur xcode 9 ios11 je l'obtiens étiré. le cadre du bouton doit être 32x32, lors de la vérification de la carte SIM et de l'obtention de la vue et en disant à xcode de décrire la vue que j'obtiens en 170x32 ou quelque chose comme ça.

voici mon code.

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

    }

entrez la description de l'image ici

lorenzo gonzalez
la source
Avez-vous utilisé la vue pile dans la barre de navigation?
Vlad Khambir
@ V.Khambir Nop ...: /
lorenzo gonzalez
ce rapport de bogue est-il quelque part?
Edu du
iOS 11 utilise la mise en page automatique pour mettre en page les éléments de navigation. Au cas où vous auriez besoin de déplacer l' UIButtonintérieur UIBarButtonItem, utilisezbutton.imageEdgeInsets = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: -20)
onmyway133

Réponses:

188

Raison

Le problème apparaît car à partir d'ios 11 UIBarButtonItemutilise la mise en page automatique au lieu de traiter les cadres.

Solution

Vous devez ajouter une contrainte de largeur pour ce bouton d'image si vous utilisez Xcode 9.

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

PS

buttonn'est pas UIBarButtonItem, il est à l' UIButtonintérieur UIBarButtonItem. Vous ne devez pas définir de contrainte pour UIBarButtonItem, mais pour les éléments à l'intérieur.

Vlad Khambir
la source
3
@ V.Khambir maintenant je reçois ce problème. Mais avec cette même solution avec xcode 9, et si je cours dans un appareil ios 1, c'est très bien ... Comment puis-je résoudre ce problème pour toutes les versions. J'ai vérifié dans l'appareil des deux ios 11, ios 10. Ne montrant que bon dans la version ios 1. dans iOS 10, l'image ne s'affiche pas du tout
david
@spikesa, cela devrait fonctionner sur les deux versions iOS, vous avez probablement défini des contraintes incorrectes.
Vlad Khambir
@ V.Khambir La valeur de type 'UIBarButtonItem' n'a pas de membre 'widthAnchor' dans Xcode 9 à l'intérieur d'un if #available (iOS 11.0, *) conditionnel?
Ryan Brodie
1
@jped avez-vous trouvé une solution pour cela? Cela ne fonctionne pas non plus pour moi sur iOS 10 avec Xcode 9
swalkner
1
Génial. Je dois adorer ces changements révolutionnaires. Apple a-t-il documenté une liste de ces types de modifications sur une page ou des notes de publication quelque part?
GONeale
53

Merci à tous pour votre contribution! vous avez raison!. pour xcode9 ios11, vous devez mettre une contrainte.

 let widthConstraint = button.widthAnchor.constraint(equalToConstant: 32)
 let heightConstraint = button.heightAnchor.constraint(equalToConstant: 32)
 heightConstraint.isActive = true
 widthConstraint.isActive = true
lorenzo gonzalez
la source
1
Cela a fonctionné pour moi aussi, mais quelqu'un peut-il expliquer pourquoi cela est nécessaire pour iOS 11 alors que cela ne l'était jamais auparavant?
stonedauwg
9
UINavigationBar met maintenant en page ses sous-vues à l'aide de la disposition automatique
mangerlahn
2
Ne faites pas la même erreur que j'ai faite: je me suis éteint translatesAutoresizingMaskIntoConstraints, puis j'ai découvert plus tard que totalement cassé iOS 9 (mais avait l'air bien sur iOS 10 et 11)
xaphod
2
Value of type 'UIBarButtonItem' has no member 'widthAnchor'dans Xcode 9 à l'intérieur d'un if #available(iOS 11.0, *)conditionnel?
Ryan Brodie
@ lorenzo-gonzalez Comment avez-vous réussi? Je suis coincé là-dessus.
Alessandro Lucarini
18

Le code Objective C est désormais obsolète. Mais pour l'utilisateur qui doit créer / maintenir des projets Objective C dans iOS 11, la traduction suivante de Swift (réponse de Karoly Nyisztor) à Objective C est utile.

//  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];
SHS
la source
Cool. En fait, j'avais aussi besoin de la version Objective-C. Btw, Xcode 9 continue de redimensionner aléatoirement les éléments de la barre de navigation dans le storyboard. Je dois revérifier à chaque fois avant de pousser mes modifications. J'espère que cela sera finalement corrigé bientôt.
Karoly Nyisztor
tu es mon héros, car j'ai besoin de refactoriser l'ancien projet avec objective-c.
Marosdee Uma
18

Eh bien, le nouveau barButtonItemutilise la mise en page automatique au lieu de traiter les cadres.

L'image que vous ajoutiez au bouton est plus grande que la taille du bouton lui-même. C'est pourquoi le bouton lui-même a été étiré à la taille de l'image. Vous devez redimensionner l'image pour qu'elle corresponde à la taille du bouton nécessaire, avant de l'ajouter au bouton.

Ahmad Farrag
la source
14

J'ai écrit une petite extension pour définir les contraintes sur les éléments de la barre de navigation:

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))
Karoly Nyisztor
la source
Bonne idée! Appliqué celui-ci UIButtonfonctionne très bien.
Alessandro Ornano
12

J'ai fait cela en objectif en utilisant les lignes suivantes:

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;

Merci Bon codage !!

Aleem
la source
7

Ce que j'ai fait?

Dans mon application, j'ai ajouté une image de profil sur navigationBar à l'élément rightBarButton. avant iOS 11, il fonctionnait bien et s'affichait correctement, mais une fois mis à jour vers iOS 11, changez de comportement comme coup

entrez la description de l'image ici

J'ai donc ajouté l' UIViewélément du bouton droit et défini UIButtoncomme sous-vue de UIView? Comme ci-dessous,

entrez la description de l'image ici

Et j'ai défini des contraintes de hauteur et de largeur de UIButton.

entrez la description de l'image ici entrez la description de l'image ici

Et mon problème est résolu. N'oubliez pas de définir UIViewla couleur d'arrière-plan de la couleur claire .

REMARQUE: Si votre bouton ne fonctionne pas, vérifiez que votre UIView'shauteur peut être de 0 ici, vous devez changer la hauteur de 0 à 44 ou ce que vous voulez. Et faites aussi clipToBound = true, maintenant vous pouvez définir la position de votre bouton et cela fonctionnera bien.

iPatel
la source
Cela fonctionne, mais le bouton cesse de fonctionner lorsque vous l'ajoutez dans une vue. Des conseils?
eonist
@GitSync Vérifiez la hauteur de votre vue, elle sera de 0, changez-la en 44 ou ce que vous voulez et faites clipToBound = true, puis réglez le bouton.
iPatel
1
Sensationnel. travaux!
Conseil de
la vue du conteneur est-elle nécessaire? Ne puis-je pas simplement utiliser UIButton directement?
igrek
5

Changer le widthAnchor / heightAnchorne fonctionnera que sur les appareils iOS 11+. Pour les appareils iOS 10, vous devez utiliser la méthode classique de modification manuelle des cadres. Le fait est qu'aucune des deux approches ne fonctionne pour les deux versions, vous devez donc absolument alterner par programme en fonction de la version d'exécution, comme ci-dessous:

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
}
Malloc
la source
1
Merci pour le conseil iOS 10! Le correctif iOS 11 fonctionnait mais je ne pouvais pas le comprendre pour iOS 10.
Clifton Labrum
3

Même si iOS 11 utilise Autolayout pour la barre de navigation, il est possible de le faire fonctionner traditionnellement en définissant des cadres. Voici mon code fonctionnant pour ios11 et ios10 ou plus:

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

et voici comment l'élément de barre est composé:

    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
Leszek Zarna
la source
3

Mettre des contraintes par programme a fonctionné pour moi pour les utilisateurs exécutant iOS 11.X. Cependant, le bouton de la barre était toujours étiré pour les utilisateurs exécutant iOS 10.X.Je suppose que les critiques de l'AppStore exécutaient iOS 11.X et n'ont donc pas pu identifier mon problème, mon application s'est donc préparée pour la vente et a été téléchargée.

Ma solution était de changer simplement les dimensions de mon image en 30x30 dans un autre logiciel (la dimension de l'image précédente était 120x120).

Erik Nguyen
la source
1
Étant donné que la barre de navigation dans ios10 est redimensionnée et que ios11 est mise en page automatiquement, vous devez gérer if #available (iOS 11, *) {}
Paulo Sigales
J'étais en train de passer en
revue
Excellente réponse simple. Je vous remercie. Rien d'autre ne fonctionnait et cela me rendait fou.
Bretagne
0

J'ai également eu du succès en implémentant intrinsicContentSizepour renvoyer une taille appropriée pour toute sous-classe UIView personnalisée que j'ai l'intention d'utiliser comme vue personnalisée.

Chris
la source
0

J'ai créé un élément de bouton de barre, puis je l'ai ajouté à la barre de navigation.

    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
    }()

Dans viewDidLoad ()

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

Ici, j'ai l'image de 28x28.

vinny
la source