pasek nawigacji rightbaritem błąd przycisku obrazu iOS 11

101

Ten kod działa dobrze w ios10. dostaję swoją etykietę i przycisk obrazu, który jest profilem zdjęcia użytkownika, okrągły okrągły ... ok. ale podczas uruchamiania symulatora xcode 9 ios11 dostaję go rozciągniętym. Ramka przycisku musi mieć rozmiar 32x32, podczas sprawdzania karty SIM i uzyskiwania widoku i mówienia xcode, aby opisał widok, który otrzymuję jako 170x32 lub coś podobnego.

oto mój kod.

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

    }

wprowadź opis obrazu tutaj

lorenzo gonzalez
źródło
Czy używałeś widoku stosu na pasku nawigacyjnym?
Vlad Khambir
@ V.Khambir Nop ...: /
lorenzo gonzalez
czy ten raport o błędzie jest gdzieś?
Edu
iOS 11 używa AutoLayout do układu elementów nawigacji. Jeśli potrzebujesz przesunąć UIButtonwnętrze UIBarButtonItem, użyjbutton.imageEdgeInsets = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: -20)
onmyway133

Odpowiedzi:

188

Powód

Problem pojawia się, ponieważ od ios 11 UIBarButtonItemużywa autoukładu zamiast zajmować się ramkami.

Rozwiązanie

Powinieneś dodać ograniczenie szerokości do tego przycisku obrazu, jeśli używasz Xcode 9.

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

PS

buttonnie jest UIBarButtonItem, jest w UIButtonśrodku UIBarButtonItem. Powinieneś ustawić ograniczenie nie dla UIBarButtonItem, ale dla elementów w nim zawartych .

Vlad Khambir
źródło
3
@ V.Khambir teraz mam ten problem. Ale z tym samym rozwiązaniem z xcode 9, a jeśli uruchomię na urządzeniu z systemem iOS 1, jest w porządku .. Ale jeśli uruchomię na urządzeniu w wersji z systemem iOS 10, obrazy przycisków paska w ogóle się nie wyświetlają. Jak mogę to naprawić dla wszystkich wersji. Sprawdziłem urządzenie z obu ios 11, ios 10. Pokazuje dobrze tylko w wersji ios 1. w iOS 10, obraz w ogóle się nie wyświetla
David
@spikesa, powinno działać na obu wersjach iOS, prawdopodobnie ustawiłeś nieprawidłowe ograniczenia.
Vlad Khambir
@ V.Khambir Wartość typu „UIBarButtonItem” nie ma elementu członkowskiego „widthAnchor” w Xcode 9 wewnątrz warunku if #available (iOS 11.0, *)?
Ryan Brodie
1
@jped, czy znalazłeś na to rozwiązanie? U mnie nie działa również na iOS 10 z Xcode 9
swalkner
1
Wspaniały. Uwielbiam te przełomowe zmiany. Czy firma Apple udokumentowała gdzieś listę tego typu zmian na stronie lub w informacjach o wersji?
GONeale
53

Dziękujemy wszystkim za wkład! macie rację !. dla xcode9 ios11 musisz umieścić ograniczenie.

 let widthConstraint = button.widthAnchor.constraint(equalToConstant: 32)
 let heightConstraint = button.heightAnchor.constraint(equalToConstant: 32)
 heightConstraint.isActive = true
 widthConstraint.isActive = true
lorenzo gonzalez
źródło
1
U mnie też to zadziałało, ale czy ktoś może wyjaśnić, dlaczego jest to konieczne w przypadku iOS 11, skoro nigdy wcześniej nie było?
stonedauwg
9
UINavigationBar teraz układa swoje podglądy za pomocą automatycznego układu
mangerlahn
2
Nie popełnij tego samego błędu, co ja: wyłączyłem się, translatesAutoresizingMaskIntoConstraintsa później dowiedziałem się, że iOS 9 całkowicie się zepsuł (ale wyglądał dobrze na iOS 10 i 11)
xaphod
2
Value of type 'UIBarButtonItem' has no member 'widthAnchor'w Xcode 9 wewnątrz if #available(iOS 11.0, *)warunku?
Ryan Brodie
@ lorenzo-gonzalez Jak to zrobiłeś? Utknąłem w tym.
Alessandro Lucarini
18

Kod celu C jest teraz przestarzały. Ale dla użytkownika, który musi budować / utrzymywać projekty Objective C w iOS 11, pomocne jest tłumaczenie z języka Swift (odpowiedź Karoly Nyisztor) na 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];
SHS
źródło
Chłodny. Właściwie potrzebowałem też wersji Objective-C. Przy okazji, Xcode 9 losowo zmienia rozmiar elementów paska nawigacyjnego w scenorysie. Muszę dwukrotnie sprawdzić za każdym razem, zanim wprowadzę zmiany. Mam nadzieję, że wkrótce zostanie to naprawione.
Karoly Nyisztor
jesteś moim bohaterem, ponieważ muszę zreformować stary projekt z celem-c.
Marosdee Uma
18

Cóż, nowy barButtonItemużywa autoukładu zamiast zajmować się ramkami.

Obraz, który dodawałeś do przycisku, jest większy niż sam rozmiar przycisku. Dlatego sam przycisk został rozciągnięty do rozmiaru obrazu. Musisz zmienić rozmiar obrazu, aby pasował do wymaganego rozmiaru przycisku, przed dodaniem go do przycisku.

Ahmad Farrag
źródło
14

Napisałem małe rozszerzenie do ustawiania ograniczeń dla elementów paska nawigacyjnego:

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
źródło
Świetny pomysł! Zastosowany ten UIButtondziała bardzo dobrze.
Alessandro Ornano
12

Zrobiłem to obiektywnie, używając następujących linii:

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;

Dzięki Miłego kodowania!

Aleem
źródło
7

Co ja zrobiłem?

W mojej aplikacji dodałem zdjęcie profilowe na navigationBar w pozycji rightBarButton. przed iOS 11 działał dobrze i wyświetlał się poprawnie, ale po aktualizacji do iOS 11 zmień zachowanie, takie jak cios

wprowadź opis obrazu tutaj

Więc dodałem UIViewelement prawego przycisku i ustawiłem UIButtonjako podwidok UIView? Jak poniżej,

wprowadź opis obrazu tutaj

I ustawiam ograniczenia wysokości i szerokości na UIButton.

wprowadź opis obrazu tutaj wprowadź opis obrazu tutaj

I mój problem został rozwiązany. Nie zapomnij ustawić UIViewkoloru tła na czysty kolor.

UWAGA: Jeśli twój przycisk nie działa, sprawdź, czy UIView'swysokość może wynosić 0, tutaj powinieneś zmienić wysokość z 0 na 44 lub cokolwiek chcesz. A także zrób clipToBound = true, teraz możesz ustawić pozycję swojego przycisku i będzie działać dobrze.

iPatel
źródło
To działa, ale przycisk przestaje działać po dodaniu go w widoku. Jakieś wskazówki?
eonista
@GitSync Sprawdź wysokość swojego widoku - będzie to 0 zmień go na 44 lub cokolwiek chcesz i ustaw clipToBound = true, a następnie ustaw przycisk.
iPatel
1
Łał. Pracuje! Wskazówka dla
profesjonalistów
czy widok kontenera jest konieczny? Czy nie mogę po prostu bezpośrednio użyć UIButton?
igrek
5

Zmiana widthAnchor/ heightAnchorbędzie działać tylko na urządzeniach z systemem iOS 11+. W przypadku urządzeń z systemem iOS 10 musisz przejść klasyczny sposób ręcznej zmiany ramek. Chodzi o to, że żadne z dwóch podejść nie działa dla obu wersji, więc absolutnie musisz programowo zmieniać w zależności od wersji środowiska uruchomieniowego, jak poniżej:

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
źródło
1
Dzięki za wskazówkę dotyczącą iOS 10!
Clifton Labrum,
3

Mimo że iOS 11 używa Autolayout dla paska nawigacji, możliwe jest, aby działał tradycyjnie ustawiając ramki. Oto mój kod działający dla ios11 i ios10 lub starszych:

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

a oto jak składa się element paska:

    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
źródło
3

Stawianie ograniczeń programowo działało dla mnie na użytkowników korzystających z iOS 11.X. Jednak przycisk paska był nadal rozciągnięty dla użytkowników korzystających z iOS 10.X. Wydaje mi się, że recenzenci AppStore używali iOS 11.X, więc nie mogli zidentyfikować mojego problemu, więc moja aplikacja była gotowa do sprzedaży i przesłana.

Moim rozwiązaniem była po prostu zmiana wymiarów mojego obrazu na 30x30 w innym programie (poprzedni wymiar obrazu to 120x120).

Erik Nguyen
źródło
1
Ponieważ pasek nawigacji w ios10 automatycznie zmienia rozmiar, a ios11 jest automatycznie układany, potrzebujesz obsługi z if #available (iOS 11, *) {}
Paulo Sigales
Przechodziłem przez nowe zmiany i znalazłem to pytanie, ale myślę, że ta odpowiedź, którą powinien użyć programista
Shobhakar Tiwari
Świetna, prosta odpowiedź. Dziękuję Ci. Nic innego nie działało i doprowadzało mnie to do szału.
Brittany
0

Odniosłem również sukces, wdrażając intrinsicContentSizezwracanie odpowiedniego rozmiaru dla dowolnej niestandardowej podklasy UIView, której zamierzam użyć jako niestandardowego widoku.

Chris
źródło
0

Utworzyłem przycisk paska, a następnie dodałem go do paska nawigacji.

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

W widokuDidLoad ()

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

Tutaj mam obraz 28x28.

winny
źródło