web-dev-qa-db-fra.com

iOS 11 iPhone X simulateur TabBar des icônes et des titres en superposition

Toute personne ayant un problème avec le simulateur iPhone X autour du composant UITabBar?

Les miens semblent rendre les icônes et le titre superposés, je ne suis pas sûr de ne rien manquer, je l’ai également exécuté dans le simulateur de l’iPhone 8, et un des appareils réels où l’apparence est satisfaisante, comme indiqué sur le story board.

iPhone X:

 iPhone X UITabBar bug

iPhone 8

 iPhone 8 UITabBar works

114
adrian chen

J'ai pu contourner le problème en appelant simplement invalidateIntrinsicContentSize sur la barre UITabBar dans viewDidLayoutSubviews.

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

Remarque: le bas de la barre d'onglets devra être contenu au bas de la vue principale, plutôt que dans la zone sécurisée, et la barre d'onglets ne devrait pas avoir de contrainte de hauteur.

34
David Hooper

La réponse fournie par VoidLess ne résout que partiellement les problèmes de TabBar. Cela résout les problèmes de mise en page dans la barre d’onglet, mais si vous utilisez viewcontroller qui masque la barre d’onglet, celle-ci est restituée de manière incorrecte lors des animations (pour le reproduire, il est préférable d’utiliser 2 séquences de 2, 1 voir la barre de tabulation étant rendue hors de propos). Le code ci-dessous corrige les deux problèmes. Bon travail Apple.

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 < 90) {
            size.height += bottomInset
        }
    }
    return size
}

override var frame: CGRect {
    get {
        return super.frame
    }
    set {
        var tmp = newValue
        if let superview = superview, tmp.maxY != 
        superview.frame.height {
            tmp.Origin.y = superview.frame.height - tmp.height
        }

        super.frame = tmp
        }
    }
}

Code 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 && (size.height + bottomInset < 90)) {
            size.height += bottomInset;
        }
    }

    return size;
}


- (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];
}


@end
22

Il y a une astuce par laquelle nous pouvons résoudre le problème.

Il suffit de placer votre UITabBar dans un UIView.

Cela fonctionne vraiment pour moi.

Ou vous pouvez suivre ceci Lien pour plus de détails.

19
Avineet Gupta

remplace UITabBarsizeThatFits(_) pour 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
    }
}
8
Cruz

Déplacer la barre d'onglets 1 point du bas a fonctionné pour moi.

Bien sûr, vous obtiendrez un vide que vous devrez combler d'une certaine manière, mais le texte/les icônes sont maintenant correctement positionnés.

7
deej

J'ai eu le même problème.

 enter image description here

Si je règle une constante non nulle sur la contrainte inférieure de la barre UITabBar sur la zone de sécurité:

 enter image description here

Cela commence à fonctionner comme prévu ... 

 enter image description here

C’est le seul changement que j’ai fait et je ne sais pas pourquoi cela fonctionne, mais si quelqu'un le faisait, j'aimerais bien savoir. 

7
moliveira

J'ai ajouté ceci à viewWillAppear de ma coutume UITabBarController, car aucune des réponses fournies ne fonctionnait pour moi:

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

Aha! C'est en fait magique!

J'ai finalement compris cela après des heures à maudire Apple. 

UIKit gère effectivement cela pour vous, et il semble que les éléments de la barre de tabulation décalés sont dus à une configuration incorrecte (et probablement à un bogue UIKit réel). Il n'est pas nécessaire de sous-classer ou une vue en arrière-plan.

UITabBar "fonctionnera" si elle est contrainte au bas de la vue, PAS à la zone de sécurité inférieure.

Cela fonctionne même dans le constructeur d'interface. 

Correct Setup

 Working in IB

  1. Dans l'interface constructeur, en tant qu'iPhone X, faites glisser une barre UITabBar vers l'endroit où elle s'accroche dans l'encart inférieur de la zone de sécurité. Lorsque vous le déposez, il devrait sembler correct (remplissez l’espace jusqu’au bord inférieur). 
  2. Vous pouvez ensuite faire un "Ajouter les contraintes manquantes" et IB ajoutera les contraintes appropriées et votre barre d'onglets fonctionnera comme par magie sur tous les iPhones! (Notez que la contrainte du bas semble avoir une valeur constante égale à la hauteur de la zone non sécurisée de l'iPhone X, mais que la constante est en fait égale à 0)

Parfois ça ne marche toujours pas

 Broken in IB

Ce qui est vraiment stupide, c’est que vous pouvez réellement voir le bogue dans IB aussi, même si vous ajoutez les contraintes exactes que IB ajoute dans les étapes ci-dessus!

  1. Faites glisser une barre UITabBar et ne l'attachez pas dans l'encart inférieur de la zone de sécurité
  2. Ajoutez des contraintes de début, de fin et de fond à Superview (zone non sécurisée) .__ Bizarrement, cela se corrigera si vous effectuez un "Premier et deuxième éléments inversés" dans l'inspecteur de contraintes pour la contrainte de fond. ¯_ (ツ) _/¯
5
RyanM

Corrigé en utilisant UITabBar sous-classé pour appliquer les 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
    }
}
5
VoidLess

Résolu pour moi en appelant [tabController.view setNeedsLayout]; après avoir rejeté le modal du bloc d'achèvement.

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

Mon cas était que j'avais défini une hauteur UITabBar personnalisée dans mon UITabBarController, comme ceci:

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

La suppression de ce code était la solution permettant à TabBar de s'afficher correctement sur iPhone X.

2
Gytis

La hauteur de la barre UITabBar augmente au-dessus du bouton/de la ligne de base, mais dessine la sous-vue à son emplacement d'origine et superpose la base UITabBarItem sur la sous-vue.

Pour contourner le problème, vous pouvez détecter l'iPhone X, puis réduire la hauteur de la vue de 32 pixels pour vous assurer que la barre d'onglets est affichée dans la zone sécurisée au-dessus de la ligne de base.

Par exemple, si vous créez votre TabBar par programme, remplacez

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

Avec ça:

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

NOTE: Cela pourrait bien être un bug, car la taille de la vue et la disposition de la barre d'onglets sont définies par le système d'exploitation. Il devrait probablement s'afficher conformément à la capture d'écran d'Apple dans les instructions pour l'interface humaine de l'iPhone X ici: https://developer.Apple.com/ios/human-interface-guidelines/overview/iphone-x/

2
A.Badger

Sélectionnez la barre d'onglets et cochez la case "Enregistrer les marges relatives à la zone" dans l'éditeur de l'inspecteur comme suit: 

 enter image description here

1
AnnGoro

J'ai rencontré ce problème aujourd'hui avec un UITabBar ajouté manuellement au contrôleur de vue dans le storyboard. Lors de l'alignement au bas de la zone sécurisée avec une constante de 0, le problème était résolu, mais sa valeur par 1 résolvait le problème. Avoir le UITabBar jusqu'à 1 pixel de plus que la normale était acceptable pour mon application.

1
Alan MacGregor

J'avais le même problème lorsque j'essayais de définir le cadre de UITabBar dans mon TabBarController personnalisé.

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

Quand je viens de l'ajuster à la nouvelle taille, le problème disparut

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);
}
1
Evgeny

Je me suis gratté la tête à cause de ce problème. Il semble être associé à la façon dont le tabBar est initialisé et ajouté à la hiérarchie des vues. J'ai également essayé les solutions ci-dessus, comme appeler invalidateIntrinsicContentSize, définir le cadre, et aussi bottomInsets dans une sous-classe UITabBar. Ils semblent fonctionner cependant temporairement et ils rompent avec un autre scénario ou régressent la barre d’onglet en provoquant un problème de mise en page ambigu. Lorsque je déboguais le problème, j’essayais d’attribuer les contraintes de hauteur à UITabBar et centerYAnchor, mais le problème n’a pas été résolu. J'ai réalisé dans view debugger que la hauteur de tabBar était correcte avant et après la reproduction du problème, ce qui m'a amené à penser que le problème se trouvait dans les sous-vues. J'ai utilisé le code ci-dessous pour résoudre ce problème avec succès sans faire régresser aucun autre scénario. 

- (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];
        }];
    }
}

Hypothèses: je le fais uniquement pour iPhone X, car il ne semble pas pouvoir se reproduire sur un autre appareil pour le moment. Est basé sur l'hypothèse qu'Apple ne change pas le nom de la classe UITabBarButton dans les futures versions iOS. Nous ne le faisons sur UITabBarButton que lorsque cela signifie que si Apple ajoute davantage de sous-vues internes à UITabBar, il se peut que nous devions modifier le code pour l'ajuster. 

Sachez que cela fonctionne, sera ouvert aux suggestions et améliorations! 

Il devrait être simple de créer un équivalent Swift pour cela. 

1
Rushabh

A partir de ce tutoriel:

https://github.com/eggswift/ESTabBarController

et après l’initialisation de la barre d’onglet en écrivant cette ligne dans la classe appdelegate

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

Résout mon problème de barre de tabulation.

J'espère que ça résoud ton problème

Merci

1
Siddh

Pour moi, cela a résolu tous les problèmes:

    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)
    }
0
Durdu

Pour moi, supprimez [self.tabBar setBackgroundImage:] work, c'est peut-être un bug UIKit

0
KelaKing

La solution la plus simple que j'ai trouvée consistait simplement à ajouter un espace de 0,2 point entre le bas de la barre de tabulation et le bas de la zone safeAreaLayoutGuide.bottomAnchor.

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

Pour l'iPhone, vous pouvez le faire, sous-classe UITabBarController.

class MyTabBarController: UITabBarController {

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

Allez dans Storyboard et autorisez Utilisez le Guide de présentation des zones sûres et modifiez la classe de UITabbarController en MyTabBarController

P.S Cette solution n'est pas testée dans le cas d'applications universelles et iPad. 

0
NaXir

Si vous avez une contrainte de hauteur pour la barre d'onglets, essayez de la supprimer.

Face au même problème et en supprimant cela résolu le problème. 

0
rustylepord

J'utilisais un UITabBarController dans le storyboard et au début, tout fonctionnait correctement pour moi, mais après la mise à niveau vers la version Xcode plus récente, les problèmes liés à la hauteur de la barre de tabulation ont commencé à apparaître.

Pour moi, le correctif consistait à supprimer le UITabBarController existant du storyboard et à le recréer en le faisant glisser à partir de la bibliothèque d'objets de générateur d'interface.

0
enigma

J'ai créé un nouveau UITabBarController dans mon scénario et poussé tous les contrôleurs de vue vers ce nouveau UITabBarConttoller. Donc, tout fonctionne bien dans le simulateur iPhone X.

0
Evgeniy Kubyshin

essayez de changer l'écran de démarrage avec la taille @ 3x est (3726 × 6624)

0
Sob7y