ios 11 UITabBar Проблема с позиционированием UITabBarItem

Я создал свое приложение, используя новую бета-версию Xcode 9 для ios 11. Я обнаружил проблему с UITabBar, когда элементы распространяются через UITabBar, а заголовок выравнивается по правому краю изображения. Я попытался изменить код, чтобы заставить его работать, но все равно не удалось.

iOS 10+

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

iOS 11

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

Я мог бы изменить положение заголовка с помощью tabBarItem.titlePositionAdjustment Но это не мое требование, поскольку оно должно автоматически располагаться под самим изображением. Я попытался установить tabbar.itemPositioning to UITabBarItemPositioningCentered, а также попытался изменить itemSpacing и width, но все равно не получилось. Может ли кто-нибудь помочь мне понять, почему это происходит и как это исправить? Я хочу, чтобы ему нравилась версия iOS 10+, а изображения брались из крайнего левого угла iPad.


person Gihan    schedule 29.06.2017    source источник
comment
Это фича, а не баг.   -  person matt    schedule 24.08.2017
comment
Это проблема не только с target-c, но и вообще с target-c и быстрым приложением.   -  person Jeet    schedule 24.09.2017
comment
Особенность? я не знаю. Скорее Apple что-то улучшает, не задумываясь о последствиях.   -  person William Jockusch    schedule 31.12.2017
comment
Что такое последствия. Это работает так только тогда, когда для этого достаточно места. Apple заботится обо всем... это фича. Мы должны купить им бутылку вина за это;) Теперь больше места для взаимодействия с пользователем. Пространство теперь полностью пригодно для использования.   -  person Bartłomiej Semańczyk    schedule 04.01.2018


Ответы (7)


Я поддерживаю большое приложение для iPad, написанное в основном на Objective-C, которое выдержало несколько выпусков iOS. Я столкнулся с ситуацией, когда мне понадобился внешний вид панели вкладок до iOS 11 (со значками над заголовками, а не рядом с ними) для пары панелей вкладок. Мое решение состояло в том, чтобы создать подкласс UITabBar, который переопределяет метод traitCollection, чтобы он всегда возвращал компактную по горизонтали коллекцию признаков. Это заставляет iOS 11 отображать заголовки под значками для всех кнопок панели вкладок.

Чтобы использовать это, установите пользовательский класс панелей вкладок в раскадровке на этот новый подкласс и измените все выходы в коде, которые указывают на панели вкладок, на этот новый тип (не забудьте импортировать файл заголовка ниже).

В этом случае файл .h практически пуст:

//
//  MyTabBar.h
//

#import <UIKit/UIKit.h>

@interface MyTabBar : UITabBar

@end

Вот файл .m с реализацией метода traitCollection:

//
//  MyTabBar.m
//

#import "MyTabBar.h"

@implementation MyTabBar

// In iOS 11, UITabBarItem's have the title to the right of the icon in horizontally regular environments
// (i.e. the iPad).  In order to keep the title below the icon, it was necessary to subclass UITabBar and override
// traitCollection to make it horizontally compact.

- (UITraitCollection *)traitCollection {
    return [UITraitCollection traitCollectionWithHorizontalSizeClass:UIUserInterfaceSizeClassCompact];
}

@end
person John C.    schedule 29.08.2017
comment
Я не использую раскадровку/IB, но мне удалось получить точно такой же эффект, создав подкласс UITabBarController вместо UITabBar и переопределив тот же метод traitCollection. - person massimobio; 31.08.2017
comment
Не только! Он также работает с раскадровкой/IB, которые используют подклассы UITabBarController с этим исправлением... - person Daniele Ceglia; 07.09.2017
comment
На самом деле поцарапайте это. Создание подкласса UITabBarController не рекомендуется, и фактически при этом панель навигации сломалась в iOS 11 GM. - person massimobio; 19.09.2017
comment
Любая идея о том, как программно использовать подкласс UITabBar в стандартном UITabBarController? - person massimobio; 19.09.2017
comment
@massimobio создайте раскадровку и создайте свой UITabBarController в коде. (Шутки в сторону.) - person nolanw; 24.09.2017
comment
К сожалению, это нарушает внешний вид панели навигации (UIBarButtonItems и заголовок панели навигации): forums.developer.apple .com/thread/86013 - person Niko Zarzani; 02.10.2017
comment
@NikoZarzani Это нарушает внешний вид панели навигации, только если вы подклассируете UITabBarController. В случае, если вы подклассируете UITabBar, внешний вид панели навигации остается прежним. - person Eugene Brusov; 10.01.2018
comment
К сожалению, в iOS 13 появилось это предупреждение Class MyClass overrides the -traitCollection getter, which is not supported. If you're trying to override traits, you must use the appropriate API. - person zaitsman; 26.09.2019
comment
Да, iOS 13 выдавала мне те же ошибки, но если вместо этого вы используете приведенное ниже решение @andy-c, большинство этих сообщений об ошибках исчезают. Это решение по-прежнему выдает [TraitCollection]. Класс CustomiPadUITabBar переопределяет геттер -traitCollection, который не поддерживается. Если вы пытаетесь переопределить черты, вы должны использовать соответствующий API. Каким бы ни был соответствующий API? - person Seoras; 09.10.2019

Основываясь на ответе Джона С, вот версия Swift 3, которую можно использовать программно без необходимости раскадровки или подкласса:

extension UITabBar {
    // Workaround for iOS 11's new UITabBar behavior where on iPad, the UITabBar inside
    // the Master view controller shows the UITabBarItem icon next to the text
    override open var traitCollection: UITraitCollection {
        if UIDevice.current.userInterfaceIdiom == .pad {
            return UITraitCollection(horizontalSizeClass: .compact)
        }
        return super.traitCollection
    }
}
person massimobio    schedule 21.09.2017
comment
Это не рекомендуется, хотя я не удивлен, узнав, что в данный момент это работает. Если UITabBar также переопределяет traitCollection и/или если где-то есть другое расширение (или категория Objective-C) для UITabBar, которое его реализует, то результат не определен. Вам лучше создать подкласс (как это раздражает). См. stackoverflow.com/questions/5267034/category-conflicts для получения дополнительной информации. - person nolanw; 24.09.2017
comment
@nolanw Есть ли способ использовать подкласс, если вы просто используете UITabBarController? Примечание: этот ответ работает и в этом случае. - person Dan Rosenstark; 22.10.2017
comment
@DanRosenstark да: используйте раскадровку. У меня есть раскадровка в проекте с простым UITabBarController, единственной настройкой которого является установка класса панели вкладок, и я загружаю его в код. Это заноза в заднице, но это безопаснее, чем свистеть, и намного безопаснее, чем прыгать, потому что нет конфликтов категорий. - person nolanw; 23.10.2017
comment
@nolanw Вы также можете использовать отдельный файл xib с контроллером панели вкладок в качестве корневого представления в этом макете xib. Затем загрузите контроллер панели вкладок с помощью Bundle.main.loadNibNamed("MyTabBarController", owner: nil, options: [])?.first - person Eugene Brusov; 10.01.2018

Чтобы не испортить какие-либо другие черты, не лучше ли объединить их с суперклассами:

- (UITraitCollection *)traitCollection
{
  UITraitCollection *curr = [super traitCollection];
  UITraitCollection *compact = [UITraitCollection  traitCollectionWithHorizontalSizeClass:UIUserInterfaceSizeClassCompact];

  return [UITraitCollection traitCollectionWithTraitsFromCollections:@[curr, compact]];
}
person Andy C    schedule 13.09.2017
comment
Это действительно лучше! - person nolanw; 24.09.2017
comment
Круто .. это работает для меня. Когда я только что установил класс компактного размера для коллекции признаков, он исправил элементы панели вкладок, но сломал кнопки панели навигации. Спасибо!! - person Bharat Raichur; 17.10.2017
comment
@BharatRaichur Подкласс UITabBar, а не UITabBarController, затем переопределяет - (UITraitCollection *)traitCollection{...}. Это не затормозит вашу навигационную панель. - person Eugene Brusov; 10.01.2018
comment
iOS 13 выдавала в консоли большое количество отладочных сообщений о чертах, исправленных этим решением. Об одной ошибке все еще сообщается, хотя класс [TraitCollection] CustomiPadUITabBar переопределяет метод получения -traitCollection, который не поддерживается. Если вы пытаетесь переопределить черты, вы должны использовать соответствующий API. Есть идеи, как избавиться от этого? Есть ли соответствующий API? - person Seoras; 09.10.2019

Версия Swift 4 с подклассом, который позволяет избежать конфликта имен расширений/категорий:

class TabBar: UITabBar {
  override var traitCollection: UITraitCollection {
    guard UIDevice.current.userInterfaceIdiom == .pad else {
      return super.traitCollection
    }

    return UITraitCollection(horizontalSizeClass: .compact)
  }
}

Если вы используете Interface Builder и раскадровки, вы можете выбрать вид панели вкладок в своей сцене UITabBarController и изменить его класс на TabBar в инспекторе удостоверений:

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

person Max Desiatov    schedule 22.02.2018

ПРИМЕЧАНИЕ. вышеприведенное исправление, кажется, работает довольно хорошо. Не знаю, как это будет работать в будущем, но пока работает достаточно хорошо.


Согласно этому докладу WWDC, это новое поведение для:

  • айфон в альбомной ориентации
  • айпад все время

И если я правильно читаю, это поведение нельзя изменить:

У нас есть совершенно новый внешний вид панели вкладок, как в альбомной ориентации, так и на iPad, где мы показываем значок и текст рядом. И, в частности, на iPhone значок меньше, а панель вкладок меньше, чтобы дать немного больше места по вертикали.

person Dan Rosenstark    schedule 16.07.2017

В дополнение к ответу Джона:

Если у вас есть более 4 элементов панели вкладок и вам не нужна кнопка «Дополнительно», вам нужно выбрать другой класс размера. И если вам нужен исходный центрированный макет элементов, вам нужно добавить еще один метод, например:

#import "PreIOS11TabBarController.h"

@interface PreIOS11TabBarController ()

@end

@implementation PreIOS11TabBarController

// In iOS 11, UITabBarItem's have the title to the right of the icon in horizontally regular environments
// (i.e. the iPad).  In order to keep the title below the icon, it was necessary to subclass UITabBar and override
// traitCollection to make it horizontally compact.

- (UITraitCollection *)traitCollection {
    return [UITraitCollection traitCollectionWithHorizontalSizeClass:UIUserInterfaceSizeClassUnspecified];
}


- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

    self.tabBar.itemPositioning = UITabBarItemPositioningCentered;
}

@end
person twofish    schedule 12.09.2017
comment
Это решение тормозит значки панели навигации :( - person Eugene Brusov; 10.01.2018

ответ @massimobio хорош, однако из-за него большой заголовок панели навигации исчез для меня. Не исследовал проблему дальше, но это, кажется, исправляет ее:

override var traitCollection: UITraitCollection {
        guard UIDevice.current.userInterfaceIdiom == .pad else {
            return super.traitCollection
        }

        return UITraitCollection(traitsFrom: [super.traitCollection, UITraitCollection(horizontalSizeClass: .compact)])
    }
person Balázs Vincze    schedule 26.12.2019