La barre d'état et la barre de navigation apparaissent au-dessus des limites de ma vue dans iOS 7

435

J'ai récemment téléchargé Xcode 5 DP pour tester mes applications dans iOS 7. La première chose que j'ai remarquée et confirmée est que les limites de ma vue ne sont pas toujours redimensionnées pour tenir compte de la barre d'état et de la barre de navigation.

Dans viewDidLayoutSubviews, j'imprime les limites de la vue:

{{0, 0}, {320, 568}}

Il en résulte que mon contenu apparaît sous la barre de navigation et la barre d'état.

Je sais que je pourrais tenir compte de la hauteur moi-même en obtenant la hauteur de l'écran principal, en soustrayant la hauteur de la barre d'état et la hauteur de la barre de navigation, mais cela semble être un travail supplémentaire inutile.

Comment puis-je résoudre ce problème?

Mise à jour:

J'ai trouvé une solution à ce problème spécifique. Définissez la propriété translucide de la barre de navigation sur NO:

self.navigationController.navigationBar.translucent = NO;

Cela empêchera la vue d'être encadrée sous la barre de navigation et la barre d'état.

Cependant, je n'ai pas trouvé de correctif pour le cas lorsque vous souhaitez que la barre de navigation soit translucide. Par exemple, en visionnant une photo en plein écran, je souhaite que la barre de navigation soit translucide et que la vue soit encadrée en dessous. Cela fonctionne, mais lorsque je bascule pour afficher / masquer la barre de navigation, j'ai rencontré des résultats encore plus étranges. La première sous-vue (un UIScrollView) obtient ses limites y l'origine changée à chaque fois.

beebcon
la source
Je reçois également le même problème dans xcode 5 DP
Gopesh Gupta
Faites-moi savoir si vous obtiendrez une solution
Gopesh Gupta
1
Cherchez dans la barre de navigation une propriété de couleur de teinte, vous devriez pouvoir changer cette couleur bleue en celle que vous voulez.
beebcon
9
Je déteste parfois la mise à niveau d'ios car Apple ne vous a jamais donné la possibilité de garder votre application rétrocompatible.
Bagusflyer
3
Si le problème est lié à la vue passant sous la barre d'état après avoir masqué la barre supérieure du contrôleur de navigation, je me référerais à la réponse de @Stunner stackoverflow.com/a/18976660/235206 comme solution
MiKL

Réponses:

495

Vous pouvez y parvenir en implémentant une nouvelle propriété appelée edgesForExtendedLayoutdans le SDK iOS7. Veuillez ajouter le code suivant pour y parvenir,

if ([self respondsToSelector:@selector(edgesForExtendedLayout)])
        self.edgesForExtendedLayout = UIRectEdgeNone;

Vous devez ajouter ce qui précède dans votre -(void)viewDidLoadméthode.

iOS 7 apporte plusieurs modifications à la façon dont vous mettez en page et personnalisez l'apparence de votre interface utilisateur . Les changements dans la disposition du contrôleur de vue, la couleur de teinte et la police affectent tous les objets UIKit de votre application. De plus, les améliorations apportées aux API de reconnaissance des gestes vous offrent un contrôle plus fin des interactions gestuelles.

Utilisation des contrôleurs de vue

Dans iOS 7, les contrôleurs de vue utilisent une disposition plein écran. Dans le même temps, iOS 7 vous donne un contrôle plus granulaire sur la façon dont un contrôleur de vue présente ses vues. En particulier, le concept de disposition plein écran a été affiné pour permettre à un contrôleur de vue de spécifier la disposition de chaque bord de sa vue.

La wantsFullScreenLayoutpropriété du contrôleur de vue est déconseillée dans iOS 7. Si vous spécifiez actuellement wantsFullScreenLayout = NO, le contrôleur de vue peut afficher son contenu à un emplacement d'écran inattendu lors de son exécution dans iOS 7.

Pour ajuster la façon dont un contrôleur de vue dispose ses vues, UIViewController fournit les propriétés suivantes:

  • bordsForExtendedLayout

La edgesForExtendedLayoutpropriété utilise le UIRectEdgetype, qui spécifie chacun des quatre bords d'un rectangle, en plus de spécifier aucun et tous. Permet edgesForExtendedLayoutde spécifier les bords d'une vue à étendre, quelle que soit la translucidité de la barre. Par défaut, la valeur de cette propriété est UIRectEdgeAll.

  • extendedLayoutIncludesOpaqueBars

Si votre conception utilise des barres opaques, affinez edgesForExtendedLayouten définissant également la extendedLayoutIncludesOpaqueBarspropriété sur NO . (La valeur par défaut de extendedLayoutIncludesOpaqueBarsest NO .)

  • ajuste automatiquementScrollViewInsets

Si vous ne souhaitez pas que les encarts de contenu d'une vue de défilement soient automatiquement ajustés, définissez automaticallyAdjustsScrollViewInsetssur NON . (La valeur par défaut de automaticallyAdjustsScrollViewInsetsest OUI .)

  • topLayoutGuide, bottomLayoutGuide

Les propriétés topLayoutGuideet bottomLayoutGuideindiquent l'emplacement des bords supérieurs ou inférieurs de la barre dans la vue d'un contrôleur de vue. Si des barres doivent chevaucher le haut ou le bas d'une vue, vous pouvez utiliser Interface Builder pour positionner la vue par rapport à la barre en créant des contraintes en bas topLayoutGuideou en haut de bottomLayoutGuide. (Si aucune barre ne doit chevaucher la vue, le bas de topLayoutGuideest le même que le haut de la vue et le haut de bottomLayoutGuideest le même que le bas de la vue.) Les deux propriétés sont créées paresseusement à la demande.

Veuillez vous référer, apple doc

Nandha
la source
2
Il ne se compilera pas sous iOS6. Je pense qu'il devrait être écrit comme performselector ...
Shmidt
8
Oui, c'est pourquoi j'ai inclus la vérification du sélecteur avec la condition if, if ([self respondsToSelector: @selector (bordsForExtendedLayout)])
Nandha
19
Cela ne fonctionnerait pas si je n'ai pas de barre de navigation. Dans ce cas, ma vue s'étend derrière la barre d'état.
Van Du Tran
4
J'ai le même problème que @VanDuTran. bordsForExtendedLayout n'aide pas si la barre de navigation est masquée.
fishinear
6
cela fonctionne mais ... il n'y a plus d'effet translucide ... comment pouvons-nous préserver également l'effet translucide ...
Dipu Rajak
110

Vous n'avez pas à calculer jusqu'où tout baisser, il existe une propriété intégrée pour cela. Dans Interface Builder, mettez en surbrillance votre contrôleur de vue, puis accédez à l'inspecteur d'attributs. Ici, vous verrez des cases à cocher à côté des mots "Étendre les bords". Comme vous pouvez le voir, dans la première capture d'écran, la sélection par défaut est que le contenu apparaisse sous les barres supérieure et inférieure, mais pas sous les barres opaques, c'est pourquoi la définition du style de barre sur non translucide a fonctionné pour vous.

Comme vous pouvez le constater dans la première capture d'écran, deux éléments d'interface utilisateur se cachent sous la barre de navigation. (J'ai activé les wireframes dans IB pour illustrer cela) Ces éléments, un UIButton et un UISegmentedControl ont tous deux leur origine "y" définie sur zéro, et le contrôleur de vue est défini pour autoriser le contenu sous la barre supérieure.

entrez la description de l'image ici

Cette deuxième capture d'écran montre ce qui se passe lorsque vous décochez la case "Sous les barres supérieures". Comme vous pouvez le voir, la vue des contrôleurs de vue a été déplacée vers le bas de manière appropriée pour que son origine y soit juste sous la barre de navigation.

entrez la description de l'image ici

Cela peut également être accompli par programme grâce à l'utilisation de -[UIViewController edgesForExtendedLayout]. Voici un lien vers la référence de classe pour edgeForExtendedLayout et pour UIRectEdge

[self setEdgesForExtendedLayout:UIRectEdgeNone];
Mick MacCallum
la source
15
Comment puis-je faire de même pour simplement afficher dans un .xib?
bobics
2
J'ai ajouté une étiquette en vue et j'ai suivi vos instructions, mais cela ne fonctionne pas pour moi
RMRAHUL
5
@bobics La réponse à la question XIB est: "Vous ne pouvez pas." Pas via IB de toute façon. Déposez un radar et espérez qu'Apple finira par y remédier.
memmons
Merci @ 0x7fffffff, c'était juste l'info que je cherchais et était très utile.
campo
33

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

Stunner
la source
Enfin trouvé une réponse qui fonctionne réellement pour cela. Bon travail!
StuartM
1
Pour résoudre le problème selon lequel la vue du contrôleur de vue apparaît sous la barre d'état lorsque la barre de navigation est masquée, c'est le code qui capture la vue sous la barre d'état.
MiKL
Remarque: cela poussera le bas de votre vue hors de l'écran.
memmons
1
En outre, à moins que vous construisez pour seulement iOS 7, le code ci - dessus renvoie une erreur - topLayoutGuideest seulement iOS 7.
memmons
1
Notez également que lorsque votre vue principale est une vue UITableView, viewDidLayoutSubviews sera appelé à chaque défilement. Votre UITableView sera réduite jusqu'à ce que sa hauteur soit de 15 pixels. Ajoutez un indicateur pour exécuter ce code une seule fois. ;)
Thomas Johannesmeyer
30

Solution Swift 3 / Swift 4 qui fonctionne également avec les fichiers NIB / XIB dans iOS 10+:

override func viewDidLoad() {
    super.viewDidLoad()

    edgesForExtendedLayout = []
}
flo_23
la source
C'est ce qui m'a aidé ... si simple. Merci :-)
Hernan Arber
Merci, c'est vraiment utile
Muhammad Ahmed Baig
Ceci est la meilleure solution pour 10.x Swift 3+ IMO
shokaveli
10

Si vous voulez que la vue ait la barre de navigation translucide (ce qui est plutôt sympa), vous devez configurer un contentInset ou similaire.

Voici comment je le fais:

// Check if we are running on ios7
if([[[[UIDevice currentDevice] systemVersion] componentsSeparatedByString:@"."][0] intValue] >= 7) {
      CGRect statusBarViewRect = [[UIApplication sharedApplication] statusBarFrame];
      float heightPadding = statusBarViewRect.size.height+self.navigationController.navigationBar.frame.size.height;

      myContentView.contentInset = UIEdgeInsetsMake(heightPadding, 0.0, 0.0, 0.0);
}
Magnus
la source
3
pourquoi ne pouvez-vous pas le comparer directement avec 7.0
Leena
1
lol je comprends: la comparaison avec une version spécifique avec ajout mineur est moins robuste. Mais vous êtes en train de vérifier si la valeur est PLUS GRANDE ou égale à donc la comparaison avec 7.0 ferait très bien l'affaire ici;)
EeKay
1
@leena - Il s'agit des fonctionnalités de la version 7.x et des versions ultérieures - je vérifie donc si la version est supérieure ou égale à 7 et j'ignore les révisions mineures de la vérification.
Magnus
2
J'ai eu un problème avec l'affichage de ma tableView derrière ma Tabbar. Ce qui fait que la dernière ligne de mon tableau ne défile jamais au-dessus de la barre d'onglets. Je l'ai corrigé comme ça: myTableView.contentInset = UIEdgeInsetsMake (0, 0.0, TabbarHeight, 0)
James Laurenstin
contentInsetest une propriété de UIScrollView. Et si mon point de vue principal n'est pas une sous-classe de UIScrollView. Comment puis-je résoudre le problème de chevauchement?
Pwner
9

edgesForExtendedLayoutfait l'affaire pour iOS 7. Cependant, si vous créez l'application sur le SDK iOS 7 et la déployez dans iOS 6, la barre de navigation apparaît translucide et les vues se trouvent en dessous. Donc, pour le réparer à la fois pour iOS 7 et pour iOS 6, procédez comme suit:

self.navigationController.navigationBar.barStyle = UIBarStyleBlackOpaque;
if ([self respondsToSelector:@selector(edgesForExtendedLayout)])
    self.edgesForExtendedLayout = UIRectEdgeNone;   // iOS 7 specific
Raj Pawan Gumdal
la source
9

Dans le fichier plist de vos applications, ajoutez une ligne, appelez-la "Afficher l'apparence de la barre d'état basée sur le contrôleur" et définissez-la sur NO .

Idan
la source
7

L'astuce la plus simple consiste à ouvrir le fichier NIB et à effectuer ces deux étapes simples:

  1. Basculez simplement cela et réglez-le sur celui que vous préférez:

Entrez la description de l'image ici

  1. Sélectionnez les UIView / UIIMageView / ... que vous souhaitez déplacer vers le bas. Dans mon cas, seul le logo était superposé et j'ai défini le delta sur +15; (OU -15 si vous avez choisi iOS 7 à l'étape 1)

Entrez la description de l'image ici

Et le résultat :

Avant Après

Riskov
la source
6
Cela fonctionne, mais cela ressemble à une solution difficile à maintenir. Il serait préférable de simplement résoudre le problème au lieu de le corriger.
NLemay
il serait préférable de le faire par programme pour toutes les sous-vues de la vue, car cela ne fonctionne pas s'il est appliqué à la vue principale
wildmonkey
5

Solution rapide:

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    self.edgesForExtendedLayout = UIRectEdge.None
}
fatihyildizhan
la source
4
C'est désormais edgeForExtendedLayout = []
Leon
1
Comme il s'agit d'une réponse publique, nous ne devons pas oublier d'appeler:super.viewWillAppear(animated)
prodos
4

Je voudrais développer la réponse de Stunner et ajouter une ifdéclaration pour vérifier s'il s'agit d'iOS-7, car lorsque je le testais sur iOS 6, mon application plantait.

L'addition ajouterait:

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

Je suggère donc d'ajouter cette méthode à votre MyViewControler.mfichier:

- (void) viewDidLayoutSubviews {
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
        CGRect viewBounds = self.view.bounds;
        CGFloat topBarOffset = self.topLayoutGuide.length;
        viewBounds.origin.y = topBarOffset * -1;
        self.view.bounds = viewBounds;
    }
}
werdsackjon
la source
4

Swift 3

override func viewWillAppear(_ animated: Bool) {
    self.edgesForExtendedLayout = []
}
Shahrukh
la source
3

J'ai un scénario où j'utilise le BannerViewController écrit par Apple pour afficher mes annonces et un ScrollViewController intégré dans le BannerViewController.

Pour empêcher la barre de navigation de masquer mon contenu, j'ai dû apporter deux modifications.

1) Modifier BannerViewController.m

- (void)viewDidLoad
{
   [super viewDidLoad];
   float systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
   if (systemVersion >= 7.0) {
      self.edgesForExtendedLayout = UIRectEdgeNone;
   }
}

2) Modifier mon ScrollViewContoller

- (void)viewDidLoad
{
    [super viewDidLoad];
    float systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
    if (systemVersion >= 7.0) {
        self.edgesForExtendedLayout = UIRectEdgeBottom;
    }
}

Maintenant, les annonces s'affichent correctement en bas de la vue au lieu d'être couvertes par la barre de navigation et le contenu en haut n'est pas coupé.

Xavier John
la source
2

il suffit de définir le code suivant en vue apparaîtra.

  if ([[[UIDevice currentDevice] systemVersion] floatValue]<= 7) {
self.edgesForExtendedLayout = UIRectEdgeNone;
 }
Amit Shelgaonkar
la source
C'est la seule chose qui a fonctionné dans ma situation.
goobliata
2

créer une contrainte à la disposition supérieure comme celle-ci entrez la description de l'image ici

carmen_munich
la source
2

Swift 4.2 - Xcode 10.0 - iOS 12.0:

if #available(iOS 11.0, *) {} else {
  self.edgesForExtendedLayout = []
  self.navigationController?.view.backgroundColor = .white
}
juliancadi
la source
1

Pour moi, la solution la plus simple consiste à ajouter deux clés dans le plist

entrez la description de l'image ici

giuseppe
la source
+1, j'avais la "Barre d'état initialement cachée" = OUI, mais en ajoutant "Afficher l'apparence de la barre d'état basée sur le contrôleur" = NON, je me suis débarrassé de la barre d'état.
Jonas Byström
1

Ajoutez la clé "Afficher l'apparence de la barre d'état basée sur le contrôleur" dans la liste déroulante sous la forme d'une ligne info.plist. Quelque chose comme ça:

Entrez la description de l'image ici

Kursat Turkay
la source
intéressant.il a aidé sur mes projets cocos2d.que je bascule cette option, je peux voir que la barre d'état supérieure est complètement partie ou apparaît.
Kursat Turkay
1

J'ai eu le même problème avec mon application sur les iPads (armv7, armv7s, amr64) qu'en présentant un autre UIViewController et après les avoir rejetés, la barre de navigation s'affiche sous la barre d'état ... Je passe beaucoup de temps à trouver une solution pour cela. J'utilise le storyboard et dans InterfaceBuilder pour UIViewController, ce qui rend terrible la définition de la présentation à partir de FullScreen -> Contexte actuel et cela résout ce problème. Cela fonctionne dans mon application uniquement pour les iPads => iOS8.0 (test avec iOS8.1) et pour les iPads avec iOS 7.1 ne fonctionne pas !!voir capture d'écran

Alexej W.
la source
Dans mon cas, ma vue principale chevauchait ma tabBar et je n'avais aucune idée pourquoi. Il s'avère que l'option Étendre les bords> Sous les barres inférieures a été vérifiée. Il était vraiment difficile de le remarquer car l'arrière-plan de mon application était blanc et cela ne générait qu'une certaine opacité sur ma barre de tabulation. Merci!
Jesus Rodriguez
0

Étapes pour masquer la barre d'état dans iOS 7:

1.Accédez au fichier info.plist de votre application.

2.Et définir, afficher l'apparence de la barre d'état basée sur le contrôleur: booléen NON

J'espère que j'ai résolu le problème de la barre d'état .....

chandrika
la source
0

Dans mon cas, avoir loadView () a interrompu
ce code: self.edgesForExtendedLayout = UIRectEdgeNone

mais après avoir supprimé loadView () tout a bien fonctionné

DevB2F
la source