44 votes

Orientation dans une UIView ajoutée à une UIWindow

J'ai une UIView qui est censée couvrir l'ensemble du dispositif (UIWindow) pour prendre en charge un effet de zoom avant/arrière sur une image que je réalise à l'aide d'une animation de base où un utilisateur appuie sur un bouton d'une UITableViewCell et je fais un zoom sur l'image associée.

Le zoom fonctionne parfaitement, mais je n'ai pas réussi à comprendre pourquoi la vue secondaire est toujours en mode portrait alors que l'appareil est en mode paysage. Une illustration ci-dessous :

enter image description here

J'ai bien un contrôleur de navigation mais cette vue a été ajoutée directement à la UIWindow.

0 votes

Cette réponse vous aide-t-elle ? stackoverflow.com/a/3368786/419 Si c'est le cas, pouvez-vous l'accepter à la place ?

121voto

dizy Points 3755

Vous pouvez lire ici quelques-unes des causes possibles :
Q&A QA1688 - Pourquoi mon UIViewController ne tourne-t-il pas avec l'appareil ?

Dans votre situation, c'est probablement le fait que vous ajoutez la vue comme une autre sous-vue à la fenêtre. Seule la première sous-vue reçoit les événements de rotation. Ce que vous pouvez faire, c'est l'ajouter comme une sous-vue de la première sous-vue de la fenêtre.

UIWindow* window = [UIApplication sharedApplication].keyWindow;
if (!window) 
    window = [[UIApplication sharedApplication].windows objectAtIndex:0];
[[[window subviews] objectAtIndex:0] addSubview:myView];

0 votes

C'est incroyable - merci d'avoir indiqué le lien QA. Dans les documents officiels, ce n'est pas documenté (j'ai parcouru les guides de programmation View et Window, ainsi que les classes UIWindow et UIView, et je n'ai trouvé aucune mention à ce sujet), et il s'agit clairement d'un bogue important (qu'Apple n'a pas l'intention de corriger, à en juger par le ton de l'article de QA).

14 votes

L'ajout à la première vue secondaire ne fonctionnera pas si vous voulez afficher devant un contrôleur de vue modal (au moins à partir d'iOS5), car les contrôleurs de vue modaux sont ajoutés en tant que deuxième hiérarchie de vue sur les vues secondaires principales de UIWindow.

0 votes

@FábioOliveira :- +1, Merci d'avoir souligné l'inconvénient de ce système, je le garderai aussi à l'esprit :)

83voto

hfossli Points 6815

Le problème

À partir d'iOS 6, seul le contrôleur de vue le plus haut placé (avec l'objet l'objet UIApplication) participe à la décision de pivoter ou non en en réponse à un changement d'orientation de l'appareil.

https://developer.apple.com/library/content/qa/qa1688/_index.html

La solution

J'ai ouvert un pod nommé AGWindowView .
Il traitera automatiquement les rotations et les changements de cadre, de sorte que vous n'aurez pas à vous en préoccuper.

Le code

Il prend en charge toute combinaison de SDK et de versions du système iOS. Le code correspondant peut être trouvé ici : https://github.com/hfossli/AGWindowView/blob/master/Source/AGWindowView.m

1 votes

C'est une librairie vraiment géniale ! Merci !

1 votes

Code très utile pour un projet sur lequel je travaille et qui doit présenter des vues en plus de ce qui est actuellement affiché. Excellent. Je vous remercie !

0 votes

Vous êtes un sauveur. J'aurais aimé trouver ça il y a quelques heures !

4voto

Jon Points 315

J'ai créé une catégorie sur UIApplication qui a une propriété et une méthode d'aide pour obtenir la première sous-vue de la keyWindow. C'est la vue que vous voulez superposer de toute façon. Maintenant, lorsque vous ajoutez une vue gérée par un UIViewController à cette vue, la méthode shouldRotateToInterfaceOrientation : est appelée.

UIApplication+WindowOverlay.h

#import <UIKit/UIKit.h>

@interface UIApplication(WindowOverlay)

    @property (nonatomic, readonly) UIView *baseWindowView;

    -(void)addWindowOverlay:(UIView *)view;

@end

UIApplication+WindowOverlay.m

#import "UIApplication+WindowOverlay.h"

@implementation UIApplication(WindowOverlay)

    -(UIView *)baseWindowView{
        if (self.keyWindow.subviews.count > 0){
            return [self.keyWindow.subviews objectAtIndex:0];
        }
        return nil;
    }

    -(void)addWindowOverlay:(UIView *)view{
        [self.baseWindowView addSubview:view];
    }
@end

et voici comment vous l'utiliseriez.

//at the top of the file...or in {yourproject}.pch
#import "UIApplication+WindowOverlay.h

//in a method:

UIView *view = [UIView new];

UIView *window = [UIApplication sharedApplication].baseWindowView;

view.frame = window.bounds;

[window addSubview:view];

//or

[[UIApplication sharedApplication] addWindowOverlay:view];

0 votes

Qu'en est-il de l'obtention des événements de changement d'orientation ?

0 votes

Votre vue sera tournée et le masque de taille automatique sera respecté si vous utilisez cette méthode. elle est basée sur ce qui aurait dû être la réponse acceptée ci-dessus. Je n'ai pas de réponse pour obtenir les événements de rotation spécifiquement, mais je suis sûr que cela a été répondu quelque part ailleurs.

1 votes

Ok. J'ai manqué la partie qui était une sous-vue de la première sous-vue de la fenêtre. Ensuite, un problème avec cette approche est que vous ne pouvez pas le présenter à partir d'un contrôleur de vue modal. Peut-être que si vous l'ajoutez comme une sous-vue des sous-vues de la dernière fenêtre. De cette façon, si vous avez un contrôleur de vue modale qui s'affiche, vous avez deux sous-vues sur la fenêtre principale : la vue du contrôleur de vue racine et la vue de gradation du contrôleur de vue modale et vous voulez l'ajouter à la vue de gradation, de sorte qu'elle s'affiche en haut.

1voto

Oscar Gomez Points 12966

En effet, comme vous l'avez mentionné, votre vue a été ajoutée directement à la UIWindow. Par conséquent, lorsque la méthode de rotation est appelée pour le contrôleur de navigation, rien ne se passe pour la UIWindow. L'UIView tournerait si elle était une sous-vue de la vue du contrôleur de navigation. Si pour une raison quelconque, cela ne peut pas être fait. Alors vous pourriez remplacer cette méthode :

// This method is called every time the device changes orientation
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
}

Et chaque fois que votre orientation change, vous changez aussi l'orientation de votre vue.

0voto

Kristopher Johnson Points 34554

J'ai eu un problème similaire avec des vues ajoutées directement à une fenêtre. Peut-être que cela vous aidera : Dimensionnement automatique de UIView après son ajout à la fenêtre

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X