iOS 11 iPhone X simulador UITabBar ícones e títulos sendo renderizados na parte superior cobrindo um ao outro




ios11 xcode9-beta (20)

Aha! Na verdade é mágica!

Eu finalmente percebi isso depois de horas amaldiçoando a Apple.

O UIKit realmente lida com isso para você, e parece que os itens da barra de abas deslocadas são devido a configuração incorreta (e provavelmente um bug real do UIKit). Não há necessidade de subclassificação ou de uma visualização em segundo plano.

O UITabBar "apenas funcionará" se estiver limitado à parte inferior da super visão, NÃO à área segura inferior .

Ele ainda funciona no construtor de interface.

Configuração correta

  1. No construtor de interface, exibindo como iPhone X, arraste uma UITabBar para onde ela se encaixa no inset inferior da área segura. Quando você soltá-lo, ele deve parecer correto (preencher o espaço todo o caminho até a borda inferior).
  2. Você pode então fazer um "Add Missing Constraints" e o IB adicionará as restrições corretas e sua barra de abas funcionará magicamente em todos os iPhones! (Observe que a restrição inferior parece ter um valor constante igual à altura da área não segura do iPhone X, mas a constante é, na verdade, 0)

Às vezes ainda não funciona

O que é realmente burro é que você pode ver o bug no IB também, mesmo se você adicionar as restrições exatas que o IB adiciona nas etapas acima!

  1. Arraste um UITabBar e não o encaixe na parte inferior da área segura.
  2. Adicione as restrições leading, trailing e bottom all a superview (área não segura) Estranhamente, isso se corrigirá se você fizer um "Reverse First And Second Item" no inspetor de restrição para a restrição inferior. ¯_ (ツ) _ / ¯

Alguém tendo problema com o simulador do iPhone X em torno do componente UITabBar?

O meu parece estar a renderizar os ícones e o título uns em cima dos outros, não tenho a certeza se estou a perder alguma coisa, também o corri no simulador do iPhone 8, e um dispositivo real em que parece bem tal como mostrado no story board.

iPhone X:

iPhone 8


A solução mais simples que encontrei foi simplesmente adicionar um espaço de 0,2 pt entre a parte inferior da barra de guias e a parte inferior do safeAreaLayoutGuide.bottomAnchor.

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

Corrigido usando UITabBar com subclasse para aplicar 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
    }
}

Deste tutorial:

https://github.com/eggswift/ESTabBarController

e após a inicialização da barra de abas, escrevendo esta linha na classe appdelegate

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

Resolve o meu problema de barra de abas.

Espero que isso resolva seu problema

obrigado


Eu acredito que você pode estar colocando a barra de abas contra o guia de layout seguro inferior. Provavelmente, isso não é o que você deseja, pois a barra de guias parece fazer seus próprios cálculos para posicionar os itens da barra de guias com segurança na parte superior da linha inicial do iPhone X. Configure sua parte inferior contra a parte inferior da super visão . Você deve ver que ele estabelece corretamente no iPhone X , bem como outros iPhones.


Eu adicionei isso ao viewWillAppear do meu UITabBarController personalizado, porque nenhuma das respostas fornecidas funcionou para mim:

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

Eu criei o novo UITabBarController no meu storyboard e empurrei todos os controladores de visualização para este novo UITabBarConttoller. Então, tudo funciona bem no simulador do iPhone X.


Eu encontrei esse bug no meu storyboard da tela de lançamento, que não pode ser personalizado por meio de subclasses. Depois de algumas análises, consegui descobrir a causa - eu estava usando um UITabBar diretamente. Mudar para um UITabBarController , que encapsula um UITabBar , resolveu o problema.

Nota - é possível que isso seja corrigido pelo iOS 11.1, portanto pode não afetar os aplicativos reais do iPhone X (já que é provável que o iPhone X seja lançado executando o iOS 11.1).


Eu estava tendo o mesmo problema quando eu estava tentando definir o quadro de UITabBar no meu TabBarController personalizado.

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

Quando eu apenas ajustei para o novo tamanho, a questão foi embora

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

Eu estava tendo o mesmo problema que foi resolvido, definindo os itens da tabBar após a barra de guias foi exposta.

No meu caso, o problema aconteceu quando:

  1. Existe um controlador de visualização personalizado
  2. Um UITabBar é criado no inicializador do controlador de visualização
  3. Os itens da barra de guias são definidos antes de a exibição ser carregada
  4. Na visão fez carregar a barra de abas é adicionado à vista principal do controlador de exibição
  5. Então, os itens são renderizados como você mencionou.

Eu tive o problema semelhante, no início, foi processado corretamente, mas depois de configurar o badgeValue em um dos tabBarItem ele quebrou o layout. O que funcionou para mim sem subclassificar o UITabBar foi isso, na minha subclasse UITabBarController já criada.

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

Eu usei o superview tabBar para garantir que as restrições / âncoras estivessem na mesma hierarquia de visualização e evitassem travamentos.

Com base em meu entendimento, já que isso parece ser um bug do UIKit, precisamos apenas reescrever / redefinir as restrições da barra de guias para que o mecanismo de layout automático possa fazer o layout da barra de guias novamente corretamente.


Existe um truque pelo qual podemos resolver o problema.

Basta colocar seu UITabBar dentro de um UIView.

Isso está realmente funcionando para mim.

Ou você pode seguir este Link para mais detalhes.


Mover a barra de abas 1 ponto longe do fundo funcionou para mim.

É claro que você conseguirá uma lacuna fazendo isso, o que terá que preencher de alguma forma, mas o texto / ícones estão agora corretamente posicionados.


O UITabBar está aumentando de altura para ficar acima do botão / linha inicial, mas desenhando a subvisualização em seu local original e sobrepondo o UITabBarItem à subvisão.

Como solução alternativa, você pode detectar o iPhone X e, em seguida, reduzir a altura da visualização em 32px para garantir que a barra de guias seja exibida na área segura acima da linha inicial.

Por exemplo, se você estiver criando o seu TabBar programaticamente substituir

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

Com isso:

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

NOTA: Isso pode muito bem ser um bug, já que os tamanhos das visualizações e o layout da barra de guias são definidos pelo sistema operacional. Ele provavelmente deve ser exibido de acordo com a captura de tela da Apple no iPhone X Human Interface Guidelines aqui: https://developer.apple.com/ios/human-interface-guidelines/overview/iphone-x/


Para mim isso corrigiu todos os problemas:

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

Para mim, remova o trabalho [self.tabBar setBackgroundImage:] , talvez seja bug do UIKit


Resposta fornecida por VoidLess corrige problemas de TabBar apenas parcialmente. Ele corrige problemas de layout na barra de guias, mas se você usar o viewcontroller que oculta a barra de guias, a barra de ferramentas será renderizada incorretamente durante as animações (para reproduzir, é melhor ter 2 seguidos - um modal e um push. Se você alternar os segues, veja a barra de ferramentas sendo renderizada fora do lugar). O código abaixo corrige os dois problemas. Bom trabalho maçã.

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

Código 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

Se você tiver alguma restrição de altura para a Barra de guias, tente removê-la.

Enfrentou o mesmo problema e remover isso resolveu o problema.


substituir UITabBar sizeThatFits(_) para 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
    }
}

tentar mudar a tela inicial com tamanho @ 3x é (3726 × 6624)