barra de navegación rightbaritem imagen-botón error iOS 11


101

Este código funciona bien en ios10. obtengo mi etiqueta y un botón de imagen que es el perfil de la foto del usuario, circular, redondo .. ok. pero cuando ejecuto el simulador xcode 9 ios11 lo tengo extendido. el marco del botón tiene que ser 32x32, cuando verifico el sim y obtengo la vista y le digo a xcode que describa la vista, obtengo la salida como 170x32 o algo así.

aquí está mi código.

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

    }

ingrese la descripción de la imagen aquí


¿Usó la vista de pila en la barra de navegación?
Vlad Khambir

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

¿Este informe de error está en alguna parte?
Edu

iOS 11 usa AutoLayout para diseñar elementos de navegación. En caso de que necesite cambiar el UIButtoninterior UIBarButtonItem, usebutton.imageEdgeInsets = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: -20)
onmyway133

Respuestas:


188

Razón

El problema aparece porque desde ios 11 se UIBarButtonItemusa autolayout en lugar de lidiar con frames.

Solución

Debe agregar una restricción de ancho para este botón de imagen si usa Xcode 9.

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

PD

buttonno está UIBarButtonItem, está UIButtonadentro UIBarButtonItem. Debe establecer restricciones no UIBarButtonItempara los elementos dentro de ella, sino para ella.


3
@ V.Khambir ahora estoy recibiendo este problema. Pero con esta misma solución con xcode 9, y si ejecuto en el dispositivo ios 1 está bien ... pero si ejecuto en el dispositivo de la versión ios 10 ... las imágenes de mi botón de barra no se muestran en absoluto. ¿Cómo puedo arreglar todas las versiones para esto? Revisé el dispositivo de ambos ios 11, ios 10. Solo se muestra bueno en la versión de ios 1. en ios 10, la imagen no se muestra en absoluto
david

@spikesa, debería funcionar en ambas versiones de iOS, probablemente haya establecido restricciones incorrectas.
Vlad Khambir

@ V.Khambir ¿El valor de tipo 'UIBarButtonItem' no tiene miembro 'widthAnchor' en Xcode 9 dentro de un if #available (iOS 11.0, *) condicional?
Ryan Brodie

1
@jped, ¿encontraste una solución para esto? No me funciona tan bien en iOS 10 con Xcode 9
swalkner

1
Excelente. Me encantan estos cambios rompedores. ¿Apple ha documentado una lista de este tipo de cambios en una página o notas de la versión en algún lugar?
GONeale

53

¡Gracias a todos por contribuir! ustedes tienen razón !. para xcode9 ios11 necesitas poner una restricción.

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

1
Esto también funcionó para mí, pero ¿alguien puede explicar por qué es necesario para iOS 11 cuando nunca lo fue antes?
stonedauwg

9
UINavigationBar ahora diseña sus subvistas usando Auto Layout
mangerlahn

2
No cometa el mismo error que yo: apagué translatesAutoresizingMaskIntoConstraintsy luego descubrí que iOS 9 se rompió por completo (pero se veía bien en iOS 10 y 11)
xaphod

2
Value of type 'UIBarButtonItem' has no member 'widthAnchor'en Xcode 9 dentro de un if #available(iOS 11.0, *)condicional?
Ryan Brodie

@ lorenzo-gonzalez ¿Cómo lo hiciste? Estoy atascado en esto.
Alessandro Lucarini

18

El código de Objective C está obsoleto ahora. Pero para el usuario que tiene que construir / mantener proyectos de Objective C en iOS 11, la siguiente traducción de Swift (respuesta de Karoly Nyisztor) a Objective C es útil.

//  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];

Frio. En realidad, también necesitaba la versión Objective-C. Por cierto, Xcode 9 sigue cambiando el tamaño de los elementos de la barra de navegación en el guión gráfico al azar. Tengo que volver a comprobar cada vez antes de presionar mis cambios. Espero que esto se solucione pronto.
Karoly Nyisztor

eres mi héroe, porque necesito refactorizar el proyecto antiguo con objetivo-c.
Marosdee Uma

18

Bueno, el nuevo barButtonItemusa el diseño automático en lugar de tratar con marcos.

La imagen que estaba agregando al botón es más grande que el tamaño del botón en sí. Es por eso que el botón en sí se estiró al tamaño de la imagen. Debe cambiar el tamaño de la imagen para que coincida con el tamaño del botón necesario, antes de agregarlo al botón.


14

Escribí una pequeña extensión para establecer las restricciones en los elementos de la barra de navegación:

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

¡Gran idea! Aplicado este UIButtonfunciona muy bien.
Alessandro Ornano

12

Hice esto en objetivo usando las siguientes líneas:

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;

Gracias codificación feliz !!


7

¿Lo que hice?

En mi aplicación, agregué la imagen de perfil en navigationBar en el elemento rightBarButton. antes de iOS 11 funcionaba bien y se mostraba correctamente, pero cuando se actualiza a iOS 11, cambia el comportamiento como golpe

ingrese la descripción de la imagen aquí

Entonces agregué UIViewel elemento del botón derecho y lo configuré UIButtoncomo una subvista de UIView? Como abajo,

ingrese la descripción de la imagen aquí

Y establezco restricciones de altura y ancho de UIButton.

ingrese la descripción de la imagen aquí ingrese la descripción de la imagen aquí

Y mi problema está resuelto. No olvide configurar UIViewel color de fondo como un color claro .

NOTA: Si su botón no funciona, verifique que su UIView'saltura sea 0, aquí debe cambiar la altura de 0 a 44 o lo que desee. Y también hazlo clipToBound = true, ahora puedes configurar la posición de tu botón y funcionará bien.


Esto funciona, sin embargo, el botón deja de funcionar cuando lo agrega a una vista. ¿Algun consejo?
eonista

@GitSync Comprueba la altura de tu vista, será 0, cámbiala a 44 o lo que quieras y haz clipToBound = true y luego establece el botón.
iPatel

1
Guau. ¡trabajos!
Consejo

¿Es necesaria la vista de contenedor? ¿No puedo usar UIButton directamente?
igrek

5

Cambiar el widthAnchor/ heightAnchorsolo funcionará en dispositivos iOS 11+. Para los dispositivos iOS 10, debe seguir la forma clásica de cambiar manualmente los marcos. El problema es que ninguno de los dos enfoques funciona para ambas versiones, por lo que es absolutamente necesario alternar programáticamente según la versión en tiempo de ejecución, como se muestra a continuación:

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
¡Gracias por el consejo de iOS 10! Tenía la solución de iOS 11 funcionando, pero no pude resolverla para iOS 10.
Clifton Labrum

3

Aunque iOS 11 usa Autolayout para la barra de navegación, es posible hacer que funcione estableciendo marcos de manera tradicional. Aquí está mi código que funciona para ios11 e ios10 o anteriores:

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

y así es como se compone el elemento de la barra:

    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

Poner restricciones mediante programación me funcionó para los usuarios que ejecutan iOS 11.X. Sin embargo, el botón de la barra todavía estaba estirado para los usuarios que ejecutaban iOS 10.X. Supongo que los revisores de la AppStore ejecutaban iOS 11.X, por lo que no pudieron identificar mi problema, por lo que mi aplicación se preparó para la venta y se cargó ...

Mi solución fue simplemente cambiar las dimensiones de mi imagen a 30x30 en otro software (la dimensión de la imagen anterior era 120x120).


1
Debido a que la barra de navegación en ios10 tiene un tamaño automático y ios11 tiene un diseño automático, necesita manejar con if #available (iOS 11, *) {}
Paulo Sigales

Estaba revisando los nuevos cambios y encontré esta pregunta, pero supongo que el desarrollador debería usar esta respuesta
Shobhakar Tiwari

Gran respuesta simple. Gracias. Nada más funcionaba y me estaba volviendo loco.
Brittany

0

También tuve éxito al implementar intrinsicContentSizepara devolver un tamaño apropiado para cualquier subclase de UIView personalizada que pretendo usar como customView.


0

He creado un elemento de botón de barra y luego lo agregué a la barra de navegación.

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

En viewDidLoad ()

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

Aquí tengo la imagen de 28x28.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.