панель навигации rightbaritem изображение-кнопка ошибка iOS 11

101

Этот код нормально работает в ios10. Я получаю свой ярлык и кнопку с изображением, которая представляет собой профиль с фотографией пользователя, круглая круглая .. Хорошо. но при запуске симулятора xcode 9 ios11 я растягиваю его. рамка кнопки должна быть 32x32, при проверке сима и получении представления и сообщении xcode описать представление, которое я получаю, как 170x32 или что-то в этом роде.

вот мой код.

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

    }

введите описание изображения здесь

Лоренцо Гонсалес
источник
Вы использовали представление стека на панели навигации?
Влад Хамбир 09
@ V.Khambir Nop ...: /
lorenzo gonzalez
этот отчет об ошибке где-нибудь?
Edu
iOS 11 использует AutoLayout для компоновки элементов навигации. Если вам нужно сместить UIButtonвнутреннюю часть UIBarButtonItem, используйтеbutton.imageEdgeInsets = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: -20)
onmyway133 06

Ответы:

188

Причина

Проблема появляется из-за того, что с ios 11 UIBarButtonItem вместо работы с фреймами используется автоматическая раскладка.

Решение

Вы должны добавить ограничение ширины для этой кнопки с изображением, если вы используете Xcode 9.

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

PS

buttonнет UIBarButtonItem, это UIButtonвнутри UIBarButtonItem. Вы должны установить ограничение не для UIBarButtonItem, а для элементов внутри него.

Влад Хамбир
источник
3
@ V.Khambir, теперь я получаю эту проблему. Но с тем же решением с xcode 9, и если я запускаю на устройстве ios 1, все в порядке .. Но если я запускаю устройство версии ios 10 ... изображения кнопок моей панели r вообще не отображаются. Как я могу исправить это для всех версий. Я проверил устройство обоих ios 11, ios 10. Хорошо показывает себя только в версии ios 1. в ios 10 изображение вообще не отображается
Дэвид
@spikesa, он должен работать на обеих версиях iOS, возможно, вы установили неверные ограничения.
Влад Хамбир 03
@ V.Khambir Значение типа UIBarButtonItem не имеет члена widthAnchor в Xcode 9 внутри условного условия if #available (iOS 11.0, *)?
Райан Броди
1
@jped вы нашли решение для этого? У меня это тоже не работает на iOS 10 с Xcode 9
swalkner
1
Отлично. Должен любить эти критические изменения. Записала ли Apple список этих типов изменений на странице или где-нибудь в примечаниях к выпуску?
GONeale
53

Спасибо всем за участие! вы правы, ребята !. для xcode9 ios11 вам нужно поставить ограничение.

 let widthConstraint = button.widthAnchor.constraint(equalToConstant: 32)
 let heightConstraint = button.heightAnchor.constraint(equalToConstant: 32)
 heightConstraint.isActive = true
 widthConstraint.isActive = true
Лоренцо Гонсалес
источник
1
Это тоже сработало для меня, но может ли кто-нибудь объяснить, почему это необходимо для iOS 11, когда этого никогда не было?
stonedauwg
9
UINavigationBar теперь
размещает
2
Не делайте ту же ошибку, что и я: я выключил, translatesAutoresizingMaskIntoConstraintsа потом обнаружил, что iOS 9 полностью
сломана
2
Value of type 'UIBarButtonItem' has no member 'widthAnchor'в Xcode 9 внутри if #available(iOS 11.0, *)условного?
Райан Броди
@ lorenzo-gonzalez Как ты это сделал? Я застрял на этом.
Алессандро Лукарини
18

Код Objective C сейчас устарел. Но для пользователя, который должен создавать / поддерживать проекты Objective C в iOS 11, полезен следующий перевод из Swift (ответ Кароли Нисзтор) на 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];
СВС
источник
Прохладно. Собственно, мне тоже нужна была версия Objective-C. Кстати, Xcode 9 постоянно изменяет размер элементов навигационной панели в раскадровке. Я должен перепроверять каждый раз, прежде чем вносить свои изменения. Надеюсь, это скоро будет исправлено.
Karoly Nyisztor
ты мой герой, потому что мне нужно рефакторинг старого проекта с objective-c.
Marosdee Uma
18

Что ж, в barButtonItemновинке вместо работы с фреймами используется автоматическая раскладка.

Изображение, которое вы добавляли к кнопке, больше, чем размер самой кнопки. Поэтому сама кнопка растянулась до размера изображения. Вы должны изменить размер изображения, чтобы он соответствовал размеру необходимой кнопки, прежде чем добавлять его к кнопке.

Ахмад Фарраг
источник
14

Я написал крошечное расширение для установки ограничений на элементы навигационной панели:

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))
Кароли Ништор
источник
Отличная идея! Применил эту UIButtonработу очень хорошо.
Алессандро Орнано
12

Я сделал это объективно, используя следующие строки:

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;

Спасибо, удачного кодирования !!

Алим
источник
7

Что я сделал?

В своем приложении я добавил изображение профиля на панели навигации в элемент rightBarButton. до iOS 11 он работал хорошо и правильно отображался, но при обновлении до iOS 11 измените поведение, например, удар

введите описание изображения здесь

Итак, я добавил UIViewэлемент правой кнопки и установил его UIButtonкак подпредставление UIView? Как показано ниже,

введите описание изображения здесь

И я установил ограничения по высоте и ширине UIButton.

введите описание изображения здесь введите описание изображения здесь

И моя проблема решена. Не забудьте установить UIViewцвет фона как прозрачный .

ПРИМЕЧАНИЕ: Если ваша кнопка не работает, проверьте, что ваш UIView'sрост может быть равен 0, здесь вы должны изменить высоту от 0 до 44 или как хотите. А также сделайте это clipToBound = true: теперь вы можете установить положение кнопки, и она будет работать хорошо.

iPatel
источник
Это работает, однако кнопка перестает работать, когда вы добавляете ее в представление. Какие-нибудь советы?
eonist
@GitSync Проверьте высоту вашего представления, она будет 0, измените ее на 44 или как хотите, и сделайте clipToBound = true, а затем установите кнопку.
iPatel
1
Вот это да. работает! Совет профессионала: используйте ресурсы .pdf вместо .png
eonist
нужен ли контейнерный вид? Разве я не могу просто использовать UIButton напрямую?
igrek 05
5

Изменение widthAnchor/ heightAnchorбудет работать только на устройствах iOS 11+. Для устройств с iOS 10 вам нужно пойти классическим способом ручной смены кадров. Дело в том, что ни один из двух подходов не работает для обеих версий, поэтому вам абсолютно необходимо программно чередовать в зависимости от версии среды выполнения, как показано ниже:

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
Спасибо за совет по iOS 10! У меня работало исправление iOS 11, но я не мог понять его для iOS 10.
Клифтон
3

Несмотря на то, что iOS 11 использует Autolayout для панели навигации, можно заставить ее работать, традиционно устанавливая фреймы. Вот мой код, работающий для ios11 и ios10 или старше:

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

и вот как составляется элемент бара:

    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

У меня программная установка ограничений сработала для пользователей iOS 11.X. Однако для пользователей iOS 10.X кнопка панели все еще была растянутой.Я предполагаю, что обозреватели AppStore использовали iOS 11.X, поэтому не смогли определить мою проблему, поэтому мое приложение было готово к продаже и загружено ..

Мое решение заключалось в том, чтобы просто изменить размеры моего изображения на 30x30 в другом программном обеспечении (предыдущий размер изображения был 120x120).

Эрик Нгуен
источник
1
Поскольку панель навигации в ios10 изменяет размер автоматически, а ios11 - автоматически, вам нужно использовать if #available (iOS 11, *) {}
Пауло Сигалес,
Я просматривал новые изменения и нашел этот вопрос, но я думаю, что разработчик должен использовать этот ответ
Шобхакар Тивари
Отличный, простой ответ. Спасибо. Больше ничего не работало, и это сводило меня с ума.
Бриттани
0

Я также добился успеха, реализовав intrinsicContentSizeвозврат соответствующего размера для любого настраиваемого подкласса UIView, который я собираюсь использовать в качестве customView.

Крис
источник
0

Я создал элемент кнопки панели, а затем добавил его на панель навигации.

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

В viewDidLoad ()

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

Здесь у меня изображение 28x28.

Винни
источник