IOS 11 iPhone X симулятор UITabBar иконки и заголовки отображаются сверху

Любой, кто имеет проблемы с симулятором iPhone X вокруг компонента UITabBar?

Кажется, что шахта отображает значки и заголовок друг на друга, я не уверен, что я что-то пропустил, я также запустил ее в симуляторе iPhone 8 и один из реальных устройств, где он выглядит отлично, как и показано на доске объявлений.

iPhone X:

iPhone X UITabBar bug

iPhone 8

iPhone 8 UITabBar works

Ответ 1

Мне удалось обойти эту проблему, просто позвонив invalidateIntrinsicContentSize в UITabBar в viewDidLayoutSubviews.

-(void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    [self.tabBar invalidateIntrinsicContentSize];
}

Примечание. Нижняя часть панели вкладок должна содержаться в нижней части основного вида, а не в безопасной области, а панель вкладок не должна иметь ограничения по высоте.

Ответ 2

Ответ, предоставленный VoidLess, исправляет проблемы TabBar только частично. Он исправляет проблемы с макетами на вкладке, но если вы используете viewcontroller, который скрывает вкладку, вкладка отображается неправильно во время анимации (для воспроизведения лучше всего 2 имеют 2 segues - один модальный и один нажатие. Если вы чередуете segues, вы можете см. вкладку, которая отображается неуместно). В приведенном ниже коде устранены обе проблемы. Хорошая работа яблока.

  class SafeAreaFixTabBar: UITabBar {

var oldSafeAreaInsets = UIEdgeInsets.zero

@available (iOS 11.0, *)
override func safeAreaInsetsDidChange() {   super.safeAreaInsetsDidChange()
   если oldSafeAreaInsets!= safeAreaInsets {       oldSafeAreaInsets = safeAreaInsets
       invalidateIntrinsicContentSize()       SuperView?.setNeedsLayout()       SuperView?.layoutSubviews()   }
}

override func sizeThatFits (_ size: CGSize) - > CGSize {   var size = super.sizeThatFits(размер)   если #доступный (iOS 11.0, *) {       let bottomInset = safeAreaInsets.bottom       если bottomInset > 0 && size.height < 50 && (size.height + bottomInset < 90) {           size.height + = bottomInset       }   }   размер возврата
}

переопределить var frame: CGRect {   получить {       return super.frame   }   задавать {       var tmp = newValue       если пусть superview = superview, tmp.maxY !=       superview.frame.height {           tmp.origin.y = superview.frame.height - tmp.height       }
       super.frame = tmp       }   }
}
Код>

Objective-C код:

  @implementation VSTabBarFix {   UIEdgeInsets oldSafeAreaInsets;
}


- (void) awakeFromNib {   [super awakeFromNib];
   oldSafeAreaInsets = UIEdgeInsetsZero;
}


- (void) safeAreaInsetsDidChange {   [super safeAreaInsetsDidChange];
   if (! UIEdgeInsetsEqualToEdgeInsets (oldSafeAreaInsets, self.safeAreaInsets)) {       [self invalidateIntrinsicContentSize];
       if (self.superview) {           [self.superview setNeedsLayout];           [self.superview layoutSubviews];       }   }
}

- (CGSize) sizeThatFits: (CGSize) size {   size = [super sizeThatFits: size];
   if (@available (iOS 11.0, *)) {       float bottomInset = self.safeAreaInsets.bottom;       if (bottomInset > 0 && size.height < 50 && & && & & > (высота + нижний набор < 90)) {           size.height + = bottomInset;       }   }
   размер возврата;
}


- (void) setFrame: (CGRect) frame {   if (self.superview) {       if (frame.origin.y + frame.size.height!= self.superview.frame.size.height) {           frame.origin.y = self.superview.frame.size.height - frame.size.height;       }   }   [super setFrame: frame];
}


@конец
Код>

Ответ 3

Есть трюк, по которому мы можем решить проблему.

Просто введите UITabBar в UIView.

Это действительно работает для меня.

Или вы можете следить за этим Link для более подробной информации.

Ответ 4

переопределить UITabBar sizeThatFits(_) для safeArea

extension UITabBar {
    static let height: CGFloat = 49.0

    override open func sizeThatFits(_ size: CGSize) -> CGSize {
        guard let window = UIApplication.shared.keyWindow else {
            return super.sizeThatFits(size)
        }
        var sizeThatFits = super.sizeThatFits(size)
        if #available(iOS 11.0, *) {
            sizeThatFits.height = UITabBar.height + window.safeAreaInsets.bottom
        } else {
            sizeThatFits.height = UITabBar.height
        }
        return sizeThatFits
    }
}

Ответ 5

Я добавил это к viewWillAppear моего пользовательского UITabBarController, потому что ни один из предоставленных ответов не работал у меня:

tabBar.invalidateIntrinsicContentSize()
tabBar.superview?.setNeedsLayout()
tabBar.superview?.layoutSubviews()

Ответ 6

Перемещение панели вкладок 1 точка от нижней части работала для меня.

Конечно, вы получите пробел, сделав так, что вам нужно будет каким-то образом заполнить, но текст/значки теперь правильно расположены.

Ответ 7

У меня такая же проблема.

enter image description here

Если я установлю любую ненулевую константу в нижнем ограничении UITabBar в безопасную область:

enter image description here

Он начинает работать как положено...

enter image description here

Это единственное изменение, которое я сделал, и я понятия не имею, почему это работает, но если кто-то и сделает, я бы хотел знать.

Ответ 8

Исправлено с помощью подкласса UITabBar для применения safeAreaInsets:

class SafeAreaFixTabBar: UITabBar {

    var oldSafeAreaInsets = UIEdgeInsets.zero

    @available(iOS 11.0, *)
    override func safeAreaInsetsDidChange() {
        super.safeAreaInsetsDidChange()

        if oldSafeAreaInsets != safeAreaInsets {
            oldSafeAreaInsets = safeAreaInsets

            invalidateIntrinsicContentSize()
            superview?.setNeedsLayout()
            superview?.layoutSubviews()
        }
    }

    override func sizeThatFits(_ size: CGSize) -> CGSize {
        var size = super.sizeThatFits(size)
        if #available(iOS 11.0, *) {
            let bottomInset = safeAreaInsets.bottom
            if bottomInset > 0 && size.height < 50 {
                size.height += bottomInset
            }
        }
        return size
    }
}

Ответ 9

Ага! Это на самом деле волшебство!

Я наконец понял это после нескольких часов ругательства Apple.

UIKit действительно обрабатывает это для вас, и кажется, что смещенные элементы панели вкладок происходят из-за неправильной настройки (и, возможно, из-за реальной ошибки UIKit). Нет необходимости в создании подклассов или в фоновом режиме.

UITabBar будет "просто работать", если он ограничен дном суперпредставления, НЕ нижним безопасным районом.

Это даже работает в Интерфейсном конструкторе.

Правильная настройка

Working in IB

  1. В конструкторе интерфейсов, при просмотре как iPhone X, перетащите UITabBar туда, где он привязан к нижней вкладке безопасной области. Когда вы уроните его, оно должно выглядеть правильно (заполните пространство до самого нижнего края).
  2. Затем вы можете сделать "Добавить недостающие ограничения", и IB добавит правильные ограничения, и ваша панель вкладок будет волшебным образом работать на всех iPhone! (Обратите внимание, что нижнее ограничение выглядит так, как будто оно имеет постоянное значение, равное высоте небезопасной области iPhone X, но на самом деле эта константа равна 0)

Иногда это все еще не работает

Broken in IB

Что действительно глупо, так это то, что вы можете увидеть ошибку и в IB, даже если вы добавите точные ограничения, которые IB добавляет в описанных выше шагах!

  1. Перетащите UITabBar и не привязывайте его к нижнему вкладышу безопасной области
  2. Добавить ведущие, конечные и нижние ограничения все в суперпредставление (небезопасная область) Как ни странно, это исправится, если вы сделаете "Инвертировать первый и второй элемент" в инспекторе ограничений для нижнего ограничения. _ (ツ) _/¯

Ответ 10

Решено для меня, вызвав [tabController.view setNeedsLayout]; после отклонения модальности в блоке завершения.

[vc dismissViewControllerAnimated:YES completion:^(){ 
     UITabBarController* tabController = [UIApplication sharedApplication].delegate.window.rootViewController;
     [tabController.view setNeedsLayout];
}];

Ответ 11

UITabBar увеличивается в высоту, чтобы быть выше домашней кнопки/линии, но рисовать subview в исходном местоположении и накладывать UITabBarItem на subview.

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

Например, если вы создаете TabBar, программно замените

self.tabBarController = [[UITabBarController alloc] init];
self.window.rootViewController = self.tabBarController;

При этом:

#define IS_IPHONEX (([[UIScreen mainScreen] bounds].size.height-812)?NO:YES)
self.tabBarController = [[UITabBarController alloc] init];    
self.window.rootViewController = [[UIViewController alloc] init] ;
if(IS_IPHONEX)
    self.window.rootViewController.view.frame = CGRectMake(self.window.rootViewController.view.frame.origin.x, self.window.rootViewController.view.frame.origin.y, self.window.rootViewController.view.frame.size.width, self.window.rootViewController.view.frame.size.height + 32) ;
[self.window.rootViewController.view addSubview:self.tabBarController.view];
self.tabBarController.tabBar.barTintColor = [UIColor colorWithWhite:0.98 alpha:1.0] ;
self.window.rootViewController.view.backgroundColor = [UIColor colorWithWhite:0.98 alpha:1.0] ;

ПРИМЕЧАНИЕ. Это может быть ошибкой, так как размеры представления и макет панели вкладок устанавливаются ОС. Вероятно, он должен отображаться в соответствии с снимком Apple в Руководстве по человеческому интерфейсу iPhone X: https://developer.apple.com/ios/human-interface-guidelines/overview/iphone-x/

Ответ 12

В моем случае я установил пользовательскую высоту UITabBar в UITabBarController, например:

  override func viewWillLayoutSubviews() {            
        var tabFrame = tabBar.frame
        tabFrame.size.height = 60
        tabFrame.origin.y = self.view.frame.size.height - 60
        tabBar.frame = tabFrame
    }

Удаление этого кода было решением для корректного отображения TabBar на iPhone X.

Ответ 13

У меня была такая же проблема, когда я пытался установить кадр UITabBar в свой пользовательский TabBarController.

self.tabBar.frame = CGRectMake(0, self.view.frame.size.height - kTabBarHeight, self.view.frame.size.width, kTabBarHeight);

Когда я только что настроил его на новый размер, проблема исчезла.

if(IS_IPHONE_X){
    self.tabBar.frame = CGRectMake(0, self.view.frame.size.height - kPhoneXTabBarHeight, self.view.frame.size.width, kPhoneXTabBarHeight);
}
else{
    self.tabBar.frame = CGRectMake(0, self.view.frame.size.height - kTabBarHeight, self.view.frame.size.width, kTabBarHeight);
}

Ответ 14

Сегодня я столкнулся с UITabBar, вручную добавленным к контроллеру представления в раскадровке, при выравнивании к нижней части безопасной области с константой 0 я бы получил проблему, но ее изменение на 1 устранило бы проблему. Наличие UITabBar на 1 пиксель больше, чем обычно, приемлемо для моего приложения.

Ответ 15

Я почесал голову над этой проблемой. Кажется, это связано с тем, как tabBar инициализируется и добавляется для просмотра иерархии. Я также пробовал решения, такие как вызов invalidateIntrinsicContentSize, установка фрейма, а также bottomInsets внутри подкласса UITabBar. Кажется, что они работают, но временно, и они ломают какой-то другой сценарий или регрессируют панель вкладок, вызывая некоторую неоднозначную проблему макета. Когда я отлаживал проблему, я попытался назначить ограничения высоты для UITabBar и centerYAnchor, однако ни одна проблема не была устранена. Я понял, что высота tabBar была правильной до и после воспроизведения проблемы, что заставило меня думать, что проблема была в подзаголовках. Я использовал приведенный ниже код, чтобы успешно решить эту проблему, не регрессируя любой другой сценарий.

- (void) viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
    if (DEVICE_IS_IPHONEX())
    {
        [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
            for (UIView *view in self.tabBar.subviews)
            {
                if ([NSStringFromClass(view.class) containsString:@"UITabBarButton"])
                {
                    if (@available (iOS 11, *))
                    {
                        [view.bottomAnchor constraintEqualToAnchor:view.superview.safeAreaLayoutGuide.bottomAnchor].active = YES;
                    }
                }
            }
        } completion:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
            [self.tabBar layoutSubviews];
        }];
    }
}

Предположения: Я делаю это только для iPhone X, поскольку на данный момент он не воспроизводится на каком-либо другом устройстве. Основывается на предположении, что Apple не изменит имя класса UITabBarButton в будущих выпусках iOS. Мы делаем это на UITabBarButton только тогда, когда означает, что если яблоки добавят больше внутренних подпрограмм в UITabBar, нам, возможно, потребуется изменить код, чтобы приспособиться к этому.

Пожалуйста, дайте понять, если это сработает, будут открыты предложения и улучшения!

Для этого должно быть просто создать быстрый эквивалент.

Ответ 16

Из этого урока:

https://github.com/eggswift/ESTabBarController

и после инициализации панели вкладок, записывающих эту строку в класс appdelegate

(self.tabBarController.tabBar as? ESTabBar)?.itemCustomPositioning = .fillIncludeSeparator

Решает мою проблему с панелью вкладок.

Надеюсь, что он решает вашу проблему.

Спасибо

Ответ 17

Выберите вкладку и установите флажок "Сохранить относительные поля области" в редакторе инспекторов следующим образом:

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

Ответ 18

Если у вас есть ограничение по высоте для панели вкладок, попробуйте удалить его.

Столкнулась с той же проблемой, и устранение этого решило проблему.

Ответ 19

Я создал новый UITabBarController в своем раскадровке и нажал все контроллеры представлений на этот новый UITabBarConttoller. Итак, все хорошо работает в симуляторе iPhone X.

Ответ 20

Для iPhone вы можете сделать это, подкласс UITabBarController.

class MyTabBarController: UITabBarController {

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    if #available(iOS 11, *) {
        self.tabBar.heightAnchor.constraint(equalToConstant: 40).isActive = true
        self.tabBar.invalidateIntrinsicContentSize()
    }
  }
}

Откройте раскадровку и разрешите Использовать руководство по планированию безопасных областей и измените класс UITabbarController на MyTabBarController

P.S Это решение не тестируется в случае универсального приложения и iPad.

Ответ 21

попробуйте изменить заставку с размером @3x (3726 × 6624)

Ответ 22

Для меня удалите [self.tabBar setBackgroundImage:] работу, возможно, это ошибка UIKit

Ответ 23

Для меня это устранило все проблемы:

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        let currentHeight = tabBar.frame.height
        tabBar.frame = CGRect(x: 0, y: view.frame.size.height - currentHeight, width: view.frame.size.width, height: currentHeight)
    }

Ответ 24

У меня была похожая проблема, сначала она отображалась корректно, но после настройки badgeValue на одном из tabBarItem он нарушил макет. То, что это работало для меня без подкласса UITabBar было таким, на моем уже созданном подклассе UITabBarController.

-(void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];
    NSLayoutYAxisAnchor *tabBarBottomAnchor = self.tabBar.bottomAnchor;
    NSLayoutYAxisAnchor *tabBarSuperviewBottomAnchor = self.tabBar.superview.bottomAnchor;
    [tabBarBottomAnchor constraintEqualToAnchor:tabBarSuperviewBottomAnchor].active = YES;
    [self.view layoutIfNeeded];
}

Я использовал superview tabBar, чтобы убедиться, что ограничения/якоря находятся в одной иерархии представлений, и избежать сбоев.

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

Ответ 25

Простейшим решением, которое я нашел, было просто добавить пространство 0,2 пт между нижней частью панели вкладок и нижней частью safeAreaLayoutGuide.bottomAnchor, как показано ниже.

tabBar.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -0.2)

Ответ 26

open override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)
}

Это работало для меня, создавая расширение на UITabBarController

Ответ 27

Я использовал UITabBarController в раскадровке, и сначала он работал нормально для меня, но после обновления до новой версии XCode он стал вызывать у меня проблемы, связанные с высотой tabBar.

Для меня исправление состояло в том, чтобы удалить существующий UITabBarController из раскадровки и заново создать, перетащив его из библиотеки объектов конструктора интерфейса.

Ответ 28

У меня была та же проблема, которая была решена путем установки элементов tabBar после того, как была выложена панель вкладок.

В моем случае проблема возникла, когда:

  • Существует настраиваемый контроллер представлений
  • UITabBar создается в инициализаторе контроллера вида
  • Элементы панели вкладок устанавливаются перед загрузкой вида
  • В результате загрузилась панель вкладок, добавленная в основной вид контроллера вида.
  • Затем элементы отображаются, как вы упоминаете.

Ответ 29

Я думаю, что это ошибка UIKit от iPhoneX. потому что он работает:

if (@available(iOS 11.0, *)) {
    if ([UIApplication sharedApplication].keyWindow.safeAreaInsets.top > 0.0) {
       self.tabBarBottomLayoutConstraint.constant = 1.0;
    }
} 

Ответ 30

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