web-dev-qa-db-fra.com

iOS 7: UITableView s'affiche sous la barre d'état

Le premier écran de mon application est un UITableViewController sans barre de navigation, ce qui signifie que le contenu passe sous la barre d'état, ce qui entraîne de nombreuses collisions de texte. J'ai ajusté les deux propriétés pour Under top bars et Adjust scroll view insets qui l'empêchent réellement de défiler sous, mais au prix de garder le haut de la vue tableau sous. J'ai essayé de régler le cadre UITableView sur un décalage de 20 pixels, mais cela ne semble pas prendre effet et, comme j'ai actuellement besoin que l'application soit compatible avec iOS 6, je ne peux pas passer à iOS 7. pour forcer l'autolayout à utiliser le guide de hauteur supérieur. Quelqu'un at-il trouvé une solution qui fonctionne pour les deux versions?

Ce que j'ai essayé: régler edgesForExtendedLayout, modifier les paramètres dans Storyboard pour Under top bars et Adjust scroll view, forcer le cadre dans une nouvelle zone.

Une image vaut mieux que mille mots: Status bar flow under

218
Nicholas Smith

Pour toute personne intéressée par la réplication, suivez simplement ces étapes:

  1. Créer un nouveau projet iOS
  2. Ouvrez le storyboard principal et supprimez la valeur par défaut/initiale UIViewController
  3. Faites glisser un nouveau UITableViewController de la bibliothèque d'objets
  4. Définissez-le comme contrôleur de vue initial
  5. Donner à la table des données de test

Si vous suivez les étapes ci-dessus, lorsque vous exécuterez l'application, vous verrez que rien, y compris la modification des cases à cocher de Xcode pour "Étendre les bords sous les barres {Haut, Bas, Opaque}", empêche la première ligne de s'afficher sous la barre d'état. vous ne pouvez pas non plus traiter cela par programmation.

Par exemple. Dans le scénario ci-dessus, les éléments suivants auront un effet non:

// These do not work
self.edgesForExtendedLayout=UIRectEdgeNone;
self.extendedLayoutIncludesOpaqueBars=NO;
self.automaticallyAdjustsScrollViewInsets=NO;

Ce problème peut être très frustrant, et je pense qu’il s’agit d’un bogue de la part d’Apple, en particulier parce qu’il apparaît dans leur propre pré-câblé UITableViewController de la bibliothèque d’objets.

Je suis en désaccord avec tous ceux qui essaient de résoudre ce problème en utilisant une forme quelconque de "Chiffres Magiques", par exemple. msgstr "utiliser un delta de 20 pixels". Ce type de programmation étroitement couplée n’est certainement pas ce que Apple veut que nous fassions ici.

J'ai découvert deux solutions à ce problème:

  • Préserver la scène de UITableViewController:
    Si vous souhaitez conserver la UITableViewController dans le storyboard, sans la placer manuellement dans une autre vue, vous pouvez incorporer la UITableViewController dans un UINavigationController (Éditeur> Intégrer dans > Contrôleur de navigation) et décochez "Affiche la barre de navigation" dans l'inspecteur. Cela résout le problème sans nécessiter de peaufinage supplémentaire et en préservant la scène de votre UITableViewController dans le scénarimage.

  • tiliser AutoLayout et incorporer la UITableView dans une autre vue (Je crois que c'est comme cela que Apple veut que nous procédions ainsi) :
    Créez un UIViewController vide et faites-y glisser votre UITableView. Ensuite, faites Ctrl-glisser de votre UITableView vers la barre d’état. Lorsque la souris se positionne au bas de la barre d'état, vous verrez une bulle de report automatique indiquant "Guide de mise en page supérieur". Relâchez la souris et choisissez "Espacement vertical". Cela indiquera au système de mise en page de le placer juste en dessous de la barre d'état.

J'ai testé les deux méthodes sur une application vide et les deux fonctionnent. Vous devrez peut-être faire quelques ajustements supplémentaires pour les faire fonctionner pour votre projet.

365
marinosb

Si vous faites des choses par programme et utilisez un UITableViewController sans un UINavigationController votre meilleur choix est de procéder comme suit dans viewDidLoad:

Swift 3

self.tableView.contentInset = UIEdgeInsets(top: 20, left: 0, bottom: 0, right: 0)

Swift plus tôt

self.tableView.contentInset = UIEdgeInsetsMake(20.0f, 0.0f, 0.0f, 0.0f);

La UITableViewController continuera à défiler derrière la barre d'état, mais ne le sera pas si elle défilera vers le haut.

85
lipka

Remarque: Cela a fonctionné pour moi pour la configuration suivante:

  • Pas de barre de navigation en haut de l'écran (la vue tableau rencontre la barre d'état)
  • La vue table est non-scrollable

Si les deux conditions ci-dessus ne sont pas remplies, votre kilométrage peut varier.

Message original

J'ai créé ma vue par programme et cela a fini par fonctionner pour moi:

- (void) viewDidLayoutSubviews {
    // only works for iOS 7+
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
        CGRect viewBounds = self.view.bounds;
        CGFloat topBarOffset = self.topLayoutGuide.length;

        // snaps the view under the status bar (iOS 6 style)
        viewBounds.Origin.y = topBarOffset * -1;

        // shrink the bounds of your view to compensate for the offset
        viewBounds.size.height = viewBounds.size.height + (topBarOffset * -1);
        self.view.bounds = viewBounds;
    }
}

Source (dans la section topLayoutGuide au bas de la page 39).

23
Stunner

Ajoutant à la première réponse:

après que la 2ème méthode ne semblait pas fonctionner initialement, j'ai fait quelques retouches supplémentaires et j'ai trouvé la solution.

TLDR; la deuxième solution de la réponse principale fonctionne presque, mais pour certaines versions de xCode, ctrl + glisser sur "Guide de mise en page supérieure" et sélectionner Espacement vertical ne fait rien. Cependant, en ajustant d'abord la taille de la vue Tableau, puis en sélectionnant "Guide de mise en page de haut en bas" fonctionne


  1. Faites glisser un ViewController vierge sur le storyboard. View Controller

  2. Faites glisser un objet UITableView dans la vue. (Pas UITableViewController). Positionnez-le au centre même en utilisant les guides de mise en page bleus.

Table ViewCenter Image

  1. Faites glisser un UITableViewCell dans le TableView. Ce sera votre cellule de réutilisation de prototype, alors n'oubliez pas de définir son identificateur de réutilisation dans l'onglet Attributs, sinon vous obtiendrez un blocage.

Add Table View CellReuse Identifier

  1. Créez votre sous-classe personnalisée de UIViewController et ajoutez les protocoles <UITableViewDataSource, UITableViewDelegate>. N'oubliez pas de définir le ViewController de votre scénario sur cette classe dans l'inspecteur d'identité.

  2. Créez une sortie pour votre TableView dans votre fichier d'implémentation et nommez-le "tableView"

Create OutlettableView

  1. Cliquez avec le bouton droit sur TableView et faites glisser la source de données et le délégué vers votre ViewController.

dataSource delegate

Maintenant, pour la partie de ne pas couper dans la barre d'état.

  1. Saisissez le bord supérieur de votre vue Table et déplacez-le vers l'un des guides de mise en page automatiques bleus en pointillés qui se trouvent près du haut

resize

  1. Maintenant, vous pouvez contrôler le glisser de la vue du tableau vers le haut et sélectionner Guide de mise en page de haut en bas

Top Space to Top Layout Guide

  1. Cela vous donnera une erreur à propos de la disposition ambiguë de TableView, juste Ajouter des contraintes manquantes et votre fait.

Add Missing Constraints

Vous pouvez maintenant configurer votre vue sous forme de tableau comme d'habitude, sans couper la barre d'état!

20
ErikAGriffin
- (void) viewDidLayoutSubviews {
    if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1) {
        self.navigationController.navigationBar.barStyle = UIBarStyleBlackOpaque;
        if ([self respondsToSelector:@selector(edgesForExtendedLayout)])
            self.edgesForExtendedLayout = UIRectEdgeNone;   // iOS 7 specific
        CGRect viewBounds = self.view.bounds;
        CGFloat topBarOffset = self.topLayoutGuide.length;
        viewBounds.Origin.y = topBarOffset * -1;
        self.view.bounds = viewBounds;
        self.navigationController.navigationBar.translucent = NO;
    }
}

https://developer.Apple.com/library/ios/documentation/userexperience/conceptual/TransitionGuide/SupportingEarlieriOS.html#//Apple_ref/doc/uid/TP40013174-CH14-SW1

11
Olzh

Voici comment l'écrire dans "Swift" Un ajustement à la réponse de @ lipka:

tableView.contentInset = UIEdgeInsetsMake(20.0, 0.0, 0.0, 0.0)
8
uplearnedu.com

Sélectionnez UIViewController sur votre storyboard et décochez l'option Étendre les bords sous les barres du haut. Travaillé pour moi :)

7
pegpeg

Pour Xcode 7, décocher la case "translucide" pour la barre de navigation a fonctionné pour moi.

enter image description here

5
David T

Cela résoudra le problème pour un UITableViewController (sans aucun nombre magique). La seule chose que je ne pouvais pas résoudre, c'est si vous êtes en ligne, auquel cas le haut de la table est trop abaissé. Si quelqu'un sait comment résoudre ce problème, merci de nous le faire savoir.

class MyTableViewController: UITableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()    
        configureTableViewTop()
    }

    override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
        coordinator.animateAlongsideTransition({ (context) -> Void in
            }, completion: { (context) -> Void in
                self.configureTableViewTop()
        })
    }

    func configureTableViewTop() { 
        tableView.contentInset.top = UIApplication.sharedApplication().statusBarFrame.height
    }
}
3
Harris

la réponse de chappjc fonctionne très bien lorsque vous travaillez avec XIB.

J'ai trouvé la solution la plus propre lors de la création de TableViewControllers par programme en encapsulant l'instance UITableViewController dans un autre UIViewController et en définissant des contraintes en conséquence.

C'est ici:

UIViewController *containerLeftViewController = [[UIViewController alloc] init];
UITableViewController *tableViewController = [[UITableViewController alloc] init];

containerLeftViewController.view.backgroundColor = [UIColor redColor];

hostsAndMoreTableViewController.view.translatesAutoresizingMaskIntoConstraints = NO;
[containerLeftViewController.view addSubview:tableViewController.view];

[containerLeftViewController addChildViewController:tableViewController];
[tableViewController didMoveToParentViewController:containerLeftViewController];

NSDictionary * viewsDict = @{ @"tableView": tableViewController.view ,
                              @"topGuide": containerLeftViewController.topLayoutGuide,
                              @"bottomGuide": containerLeftViewController.bottomLayoutGuide,
                              };
[containerLeftViewController.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[tableView]|"
                                                                                         options:0
                                                                                         metrics:nil
                                                                                           views:viewsDict]];
[containerLeftViewController.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[topGuide][tableView][bottomGuide]"
                                                                                         options:0
                                                                                         metrics:nil
                                                                                           views:viewsDict]];

A bientôt, Ben

2
tubtub

Je ne sais pas à quel point c'est kasher, mais j'ai découvert que ce schéma déplace la vue du ViewController vers le bas et fournit à la barre d'état un arrière-plan solide:

- (void)viewDidLoad {
    [super viewDidLoad];

    // Shove everything down if iOS 7 or later
    float systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
    if (systemVersion >= 7.0f) {

        // Move the view down 20 pixels
        CGRect bounds = self.view.bounds;
        bounds.Origin.y -= 20.0;
        [self.view setBounds:bounds];

        // Create a solid color background for the status bar
        CGRect statusFrame = CGRectMake(0.0, -20.0, bounds.size.width, 20);
        UIView* statusBar = [[UIView alloc] initWithFrame:statusFrame];
        statusBar.backgroundColor = [UIColor redColor];
        [self.view addSubview:statusBar];
    }

Bien sûr, remplacez redColor par la couleur de votre choix pour l’arrière-plan.

Vous devez effectuer séparément l'une des tâches pour définir la couleur des caractères/symboles dans la barre d'état. J'utilise View controller-based status bar appearance = NO et Status bar style = Opaque black style dans le plist, pour le faire globalement.

Semble fonctionner, et je serais intéressé d’entendre des bugs ou des problèmes avec elle.

2
Hot Licks

Je l'ai fait pour l'affichage Retina/Non-Retina en tant que

BOOL isRetina = FALSE;

if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
    if ([[UIScreen mainScreen] scale] == 2.0) {
        isRetina = TRUE;
    } else {
        isRetina = FALSE;
    }
}

if (isRetina) {
    self.edgesForExtendedLayout=UIRectEdgeNone;
    self.extendedLayoutIncludesOpaqueBars=NO;
    self.automaticallyAdjustsScrollViewInsets=NO;
}
1
Salim

Pour ceux qui comme moi préfèrent ne pas intégrer leur UITableViewController dans un UIViewController, essayez ceci:

Une sous-classe personnalisée UITableViewController peut ajouter une vue de masque à la vue d'ensemble de tableView. Ajoutez le masque sur viewDidAppear et supprimez le masque sur viewWillDisappear.

private var statusBarMaskView: UIView!

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    if let superview = self.tableView.superview {
        self.statusBarMaskView = UIView(frame: CGRect.zero)
        superview.insertSubview(self.statusBarMaskView, aboveSubview: self.tableView)
        self.statusBarMaskView.backgroundColor = self.tableView.backgroundColor

        // using a Nice constraint layout library to set the frame
        self.statusBarMaskView.pinTop(to: superview)
        self.statusBarMaskView.pinLeft(to: superview)
        self.statusBarMaskView.pinRight(to: superview)
        self.statusBarMaskView.addHeightConstraint(with: 22.0)
        ////
    }
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    self.statusBarMaskView.removeFromSuperview()
    self.statusBarMaskView = nil
}
1
Lee Irvine

Je pense que l’utilisation de UITableViewController pourrait être un peu différente de ce que vous avez fait auparavant. Cela a fonctionné pour moi, mais vous n'en serez peut-être pas fan. Ce que j'ai fait est d'avoir un contrôleur de vue avec une vue conteneur qui pointe vers mon UItableViewController. De cette façon, je peux utiliser le TopLayoutGuide fourni à mon scénarimage. Ajoutez simplement la contrainte à la vue du conteneur et vous devriez être pris en charge pour iOS7 et iOS6.

1
Phong Le

La solution suivante fonctionne assez bien dans le code sans utiliser de constantes magiques et les comptes de l'utilisateur qui modifie la classe de taille, par exemple. via des rotations ou des applications côte à côte sur des ipads:

- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
    [super traitCollectionDidChange:previousTraitCollection];
    // Fix up content offset to ensure the tableview isn't underlapping the status bar.
    self.tableView.contentInset = UIEdgeInsetsMake(self.topLayoutGuide.length, 0.0, 0.0, 0.0);
}
1
qix

J'ai fini par utiliser une vue supplémentaire avec l'arrière-plan souhaité, ajoutée après TableView et placée sous la barre d'état:

    self.CoverView = [[UIView alloc]init];

    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {

    self.CoverView.frame = CGRectMake(0,0,self.view.bounds.size.width,20);
    }

    self.CoverView.backgroundColor = [UIColor whiteColor];
    self.TableView = [[UITableView alloc]initWithFrame:CGRectMake(0,
    self.CoverView.bounds.size.height,XXX, YYY)];
    [self.view addSubview:self.TableView];
    [self.view addSubview:self.CoverView];

Ce n'est pas très joli, mais c'est une solution assez simple, si vous avez besoin de travailler avec des vues sans xib, et sur IOS6 et IOS7

1
lilislilit

Fonctionne pour Swift 3 - In viewDidLoad ();

let statusBarHeight = UIApplication.shared.statusBarFrame.height

let insets = UIEdgeInsets(top: statusBarHeight, left: 0, bottom: 0, right: 0)
tableView.contentInset = insets
tableView.scrollIndicatorInsets = insets

Ce code: 1. Obtient la hauteur de la barre d'état. 2. Donne au haut de la table un contenu inséré égal à la hauteur de la barre d'état. 3. Indique le même encart dans l'indicateur de défilement, de sorte qu'il apparaît sous la barre d'état.

1
Wesh RaphLola

La solution d'Abrahamchez https://developer.Apple.com/library/ios/qa/qa1797/_index.html a fonctionné pour moi comme suit. J'avais un seul contrôleur UITableview comme vue initiale. J'avais essayé le code offset et l'incorporation dans un navcon mais je n'ai pas résolu la transparence de la barre d'état.

Ajouter un Viewcontroller et en faire la vue initiale. Cela devrait vous montrer des guides de disposition supérieurs et inférieurs essentiels.

Faites glisser l'ancienne Tableview dans la vue du nouveau contrôleur.

Faites tout le nécessaire pour adapter la table au nouveau contrôleur:

Changez votre ancien fichier controller.h de vue pour qu'il hérite/sous-classe d'UIViewController au lieu de UITableViewController.

Ajoutez UITableViewDataSource et UITableViewDelegate au fichier .h du viewcontroller.

Re-connectez tout ce qui est nécessaire dans le storyboard, tel qu'une barre de recherche.

Le plus important est de définir les contraintes, comme dans le Apple Q & A. Je n'ai pas pris la peine d'insérer une barre d'outils. Pas certain de la séquence exacte. Mais une icône rouge est apparue sur les guides de mise en page, peut-être lorsque j'ai créé. J'ai cliqué dessus et laissé Xcode installer/nettoyer les contraintes.

Ensuite, j'ai cliqué partout pour trouver la contrainte d'espace vertical et modifier sa valeur maximale de -20 à 0 pour que cela fonctionne parfaitement.

0
Jack Bellis

Je faisais face à ce problème dans iOS 11 mais la mise en page était correcte pour iOS 8 - 10.3.3. Pour mon cas, j'ai défini une contrainte d'espace verticale sur Superview.Top Margin au lieu de Superview.Top, qui fonctionne pour ios 8 - 11.

enter image description here

0
DareDevil

J'avais un UISearchBar au sommet de mon UITableView et le suivant a fonctionné;

self.tableView.contentInset = UIEdgeInsetsMake(20, 0, 0, 0);
self.tableView.contentOffset = CGPointMake(0, -20);

Partagez et profitez ...

0
Sam T
override func viewDidLoad() {
 // your code

 if let nc = self.navigationController {
   yourView.frame.Origin.y = nc.navigationBar.frame.Origin.y + nc.navigationBar.frame.height
  }
}
0
wajih

Je l'ai obtenu en ajustant la taille à la forme libre

enter image description here

0
fengd

Voici un Swift 2.3. (Xcode 8.0) solution. J'ai créé une sous-classe de UITableView.

class MYCustomTableView: UITableView
{   
    override func drawRect(rect: CGRect) {
        super.drawRect(rect)
        contentInset    = UIEdgeInsetsZero
    }
}

Le contenu inséré doit toujours être zéro (par défaut). Je le règle à zéro manuellement. Vous pouvez également ajouter une méthode de vérification qui effectue la vérification et si c'est autre chose que ce que vous voulez, obtenez simplement le bon rect. Le changement ne sera reflété que lorsque la tableview sera dessinée (ce qui n'arrive pas souvent).

N'oubliez pas de mettre à jour TableView dans votre IB (dans TableViewController ou simplement TableView dans ViewController).

0
Darkwonder

J'utilise un UISplitViewController avec un contrôleur de navigation et un contrôleur de table. Cela a fonctionné pour moi dans la vue principale après avoir essayé de nombreuses solutions ici:

float systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
if (systemVersion >= 7.0f) {

    // Move the view down 20 pixels
    CGRect bounds = self.view.bounds;
    bounds.Origin.y -= 20.0;
    [self.navigationController.view setBounds:bounds];

    // Create a solid color background for the status bar
    CGRect statusFrame = CGRectMake(0.0, -20.0, bounds.size.width, 20);
    UIView* statusBar = [[UIView alloc] initWithFrame:statusFrame];
    statusBar.backgroundColor = [UIColor whiteColor];
    [statusBar setAlpha:1.0f];
    [statusBar setOpaque:YES];
    [self.navigationController.view addSubview:statusBar];
}

Elle ressemble à la solution de Hot Licks mais applique la sous-vue à navigationController.

0
sfr14