Wer hat Probleme mit dem iPhone X-Simulator rund um die UITabBar-Komponente?
Meine scheinen die Symbole und den Titel übereinander zu rendern, ich bin mir nicht sicher, ob mir etwas fehlt, ich habe es auch im iPhone 8-Simulator ausgeführt und ein Gerät, bei dem es genau so aussieht, wie es auf der Storyboard.
iPhone X:
iPhone 8
Ich konnte das Problem umgehen, indem ich invalidateIntrinsicContentSize auf der UITabBar in viewDidLayoutSubviews aufrief.
-(void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
[self.tabBar invalidateIntrinsicContentSize];
}
Hinweis: Der untere Teil der Registerkartenleiste muss sich am unteren Rand der Hauptansicht und nicht im sicheren Bereich befinden. Die Registerkartenleiste sollte keine Höhenbeschränkung haben.
Die von VoidLess bereitgestellte Antwort behebt TabBar-Probleme nur teilweise. Es behebt Layoutprobleme in der Tab-Leiste, aber wenn Sie ViewController verwenden, der die Tab-Leiste verbirgt, wird die Tab-Leiste während der Animationen falsch dargestellt (um sie zu reproduzieren, haben Sie am besten 2 Segmente - einen modalen und einen Push. Wenn Sie die Segmente wechseln, können Sie dies tun sehen, dass die Tab-Leiste nicht richtig dargestellt wird). Der folgende Code behebt beide Probleme. Gute Arbeit, 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
}
}
}
Ziel-C-Code:
@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
Es gibt einen Trick, mit dem wir das Problem lösen können.
Fügen Sie einfach Ihre UITabBar in eine UIView ein.
Das funktioniert wirklich für mich.
Oder Sie können diesem Link für weitere Details folgen.
Überschreiben Sie UITabBar
sizeThatFits(_)
für 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
}
}
Das Verschieben der Tab-Leiste 1 Punkt von unten hat für mich funktioniert.
Natürlich entsteht dadurch eine Lücke, die Sie ausfüllen müssen, aber der Text/die Symbole sind jetzt richtig positioniert.
Ich hatte das gleiche Problem.
Wenn ich für die untere Einschränkung der UITabBar eine Konstante ungleich Null für den sicheren Bereich einrichte:
Es fängt an, wie erwartet zu arbeiten ...
Das ist die einzige Änderung, die ich vorgenommen habe, und ich habe keine Ahnung, warum es funktioniert, aber wenn jemand es tut, würde ich es gerne wissen.
Ich habe dies zu viewWillAppear
meiner benutzerdefinierten UITabBarController
hinzugefügt, da keine der angegebenen Antworten für mich funktioniert:
tabBar.invalidateIntrinsicContentSize()
tabBar.superview?.setNeedsLayout()
tabBar.superview?.layoutSubviews()
Ich fand das schließlich heraus, nachdem ich Apple stundenlang beschimpft hatte.
UIKit erledigt dies tatsächlich für Sie, und es scheint, dass die Elemente der verschobenen Tab-Leiste auf falsche Einstellungen (und möglicherweise einen tatsächlichen UIKit-Fehler) zurückzuführen sind. Es ist keine Unterklasse oder eine Hintergrundansicht erforderlich.
Es funktioniert sogar im Interface Builder.
Was wirklich dumm ist, ist, dass Sie den Fehler auch in IB sehen können, selbst wenn Sie die genauen Einschränkungen hinzufügen, die IB in den obigen Schritten hinzufügt.
Behoben mit subclassed UITabBar, um safeAreaInsets anzuwenden:
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
}
}
Für mich gelöst, indem Sie [tabController.view setNeedsLayout];
aufrufen, nachdem Sie den Modal in Completion-Block abgewiesen haben.
[vc dismissViewControllerAnimated:YES completion:^(){
UITabBarController* tabController = [UIApplication sharedApplication].delegate.window.rootViewController;
[tabController.view setNeedsLayout];
}];
Mein Fall war, dass ich eine benutzerdefinierte UITabBar-Höhe in meinem UITabBarController eingestellt hatte, wie folgt:
override func viewWillLayoutSubviews() {
var tabFrame = tabBar.frame
tabFrame.size.height = 60
tabFrame.Origin.y = self.view.frame.size.height - 60
tabBar.frame = tabFrame
}
Durch das Entfernen dieses Codes konnte die TabBar auf dem iPhone X korrekt angezeigt werden.
Die Höhe der UITab-Leiste wird so erhöht, dass sie über der Home-Schaltfläche Linie liegt, zeichnet jedoch die Unteransicht an ihrer ursprünglichen Position und überlagert das UITabBarItem über der Unteransicht.
Als Problemumgehung können Sie das iPhone X erkennen und dann die Höhe der Ansicht um 32 Pixel verkleinern, um sicherzustellen, dass die Registerkartenleiste im sicheren Bereich über der Startlinie angezeigt wird.
Zum Beispiel, wenn Sie Ihre TabBar programmgesteuert ersetzen
self.tabBarController = [[UITabBarController alloc] init];
self.window.rootViewController = self.tabBarController;
Mit diesem:
#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] ;
HINWEIS: Dies kann durchaus ein Fehler sein, da die Ansichtsgrößen und das Layout der Registerkartenleiste vom Betriebssystem festgelegt werden. Es sollte wahrscheinlich laut Apple-Screenshot in den iPhone X Human Interface-Richtlinien hier angezeigt werden:/- https://developer.Apple.com/ios/human-interface-guidelines/overview/iphone-x/
Dies ist mir heute mit einer UITabBar begegnet, die manuell zum Ansichts-Controller im Storyboard hinzugefügt wurde. Wenn Sie sich mit einer Konstante von 0 am unteren Rand des sicheren Bereichs ausrichten, würde ich das Problem erhalten, aber die Änderung auf 1 würde das Problem beheben. Die UITabBar um 1 Pixel höher als normal zu haben, war für meine Anwendung akzeptabel.
Ich hatte das gleiche Problem, als ich versuchte, den Rahmen von UITabBar in meinem benutzerdefinierten TabBarController festzulegen.
self.tabBar.frame = CGRectMake(0, self.view.frame.size.height - kTabBarHeight, self.view.frame.size.width, kTabBarHeight);
Als ich es einfach an die neue Größe anpasste, ging das Problem weg
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);
}
Ich habe mir über dieses Problem den Kopf gekratzt. Es scheint zu sein, wie die Tab-Leiste initialisiert und zur Ansichtshierarchie hinzugefügt wird. Ich habe auch die obigen Lösungen ausprobiert, wie den Aufruf von invalidateIntrinsicContentSize
, das Setzen des Frames und auch bottomInsets
innerhalb einer UITabBar-Unterklasse. Sie scheinen jedoch vorübergehend zu funktionieren, und sie lösen ein anderes Szenario auf oder führen zu einer Regression der Registerkartenleiste, was zu mehrdeutigen Layoutproblemen führt. Beim Debuggen des Problems habe ich versucht, der UITabBar und dem centerYAnchor die Höhenbeschränkungen zuzuweisen. Das Problem wurde jedoch nicht behoben. In View Debugger wurde mir klar, dass die Höhe der TabBar vor und nach der Wiedergabe des Problems korrekt war. Dies führte mich zu der Annahme, dass das Problem in den Unteransichten lag. Ich habe den folgenden Code verwendet, um dieses Problem erfolgreich zu beheben, ohne ein anderes Szenario zu regressieren.
- (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];
}];
}
}
Annahmen: Ich mache dies nur für das iPhone X, da es momentan auf keinem anderen Gerät reproduziert zu werden scheint. Stützt sich auf die Annahme, dass Apple den Namen der UITabBarButton-Klasse in zukünftigen iOS-Versionen nicht ändert. Wir machen dies auf UITabBarButton nur dann, wenn bedeutet, wenn Apple weitere interne Unteransichten in UITabBar hinzufügt, müssen wir möglicherweise den Code ändern, um dies anzupassen.
Bitte, lass mich wissen, ob dies funktioniert, ist offen für Vorschläge und Verbesserungen!
Es sollte einfach sein, ein Swift-Äquivalent zu erstellen.
Aus diesem Tutorial:
https://github.com/eggswift/ESTabBarController
und nach der Initialisierung der Tab-Leiste diese Zeile in appdelegate-Klasse schreiben
(self.tabBarController.tabBar as? ESTabBar)?.itemCustomPositioning = .fillIncludeSeparator
Löst mein Problem mit der Tab-Leiste.
Hoffe, es löst dein Problem
Vielen Dank
Für mich wurden alle Probleme behoben:
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)
}
Entfernen Sie [self.tabBar setBackgroundImage:]
work für mich, vielleicht ist es ein UIKit-Fehler
Die einfachste Lösung, die ich gefunden habe, war, einfach einen Abstand von 0,2 pt zwischen dem unteren Rand der Tab-Leiste und dem unteren Teil des safeAreaLayoutGuide.bottomAnchor hinzuzufügen.
tabBar.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -0.2)
Für das iPhone können Sie dies tun, Subclass UITabBarController.
class MyTabBarController: UITabBarController {
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if #available(iOS 11, *) {
self.tabBar.heightAnchor.constraint(equalToConstant: 40).isActive = true
self.tabBar.invalidateIntrinsicContentSize()
}
}
}
Gehe zum Storyboard und erlaube Use Safe Area Layout Guide und ändere die Klasse von UITabbarController in MyTabBarController
P.S Diese Lösung wird bei universeller Anwendung und iPad nicht getestet.
Wenn Sie eine Höhenbeschränkung für die Tab-Leiste haben, versuchen Sie sie zu entfernen.
Konfrontierte das gleiche Problem und löste das Problem.
Ich hatte ein ähnliches Problem, zuerst wurde es richtig gerendert, aber nachdem ich badgeValue
auf einem der tabBarItem eingerichtet hatte, brach es das Layout. Was für mich funktionierte, ohne UITabBar
zu verwenden, war dies in meiner bereits erstellten UITabBarController
-Unterklasse.
-(void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
NSLayoutYAxisAnchor *tabBarBottomAnchor = self.tabBar.bottomAnchor;
NSLayoutYAxisAnchor *tabBarSuperviewBottomAnchor = self.tabBar.superview.bottomAnchor;
[tabBarBottomAnchor constraintEqualToAnchor:tabBarSuperviewBottomAnchor].active = YES;
[self.view layoutIfNeeded];
}
Ich habe tabBar Superview verwendet, um sicherzustellen, dass sich die Abhängigkeiten/Anker in derselben Ansichtshierarchie befinden und Abstürze vermeiden.
Da dies nach meinem Verständnis ein UIKit-Fehler zu sein scheint, müssen wir lediglich die Einschränkungen für die Tab-Leiste neu schreiben bzw. neu festlegen, damit die Auto-Layout-Engine die Tab-Leiste wieder korrekt anordnen kann.
Ich habe ein UITabBarController
im Storyboard verwendet und es funktionierte zunächst in Ordnung für mich, aber nach dem Upgrade auf eine neuere Xcode-Version gab es Probleme mit der Höhe der TabBar.
Für mich bestand der Fix darin, das vorhandene UITabBarController
aus dem Storyboard zu löschen und durch Ziehen aus der Interface Builder Objects Library neu zu erstellen.
Ich habe einen neuen UITabBarController in meinem Storyboard erstellt und alle View-Controller auf diesen neuen UITabBarConttoller übertragen. Alle funktionieren also gut mit dem iPhone X-Simulator.
versuchen Sie, den Startbildschirm mit @ 3x zu ändern (3726 × 6624).