web-dev-qa-db-fra.com

Orientation dans un UIView ajouté à une UIWindow

J'ai un UIView qui est censé couvrir tout le périphérique (UIWindow) pour prendre en charge un effet de zoom avant/arrière sur une image que je fais en utilisant une animation principale lorsqu'un utilisateur appuie sur un bouton d'un UITableViewCell et que je zoome sur l'image associée.

Le zoom fonctionne parfaitement, ce que je n'ai pas pu comprendre, c'est pourquoi la sous-vue est toujours en mode portrait, même si l'appareil est en mode paysage. Une illustration ci-dessous:

enter image description here

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

44
Ken

Vous pouvez lire sur certaines des causes possibles ici:
Questions/Réponses techniques QA1688 - Pourquoi mon UIViewController ne tourne-t-il pas avec l'appareil?

Dans votre cas, il est probablement dû au fait que vous ajoutez la vue en tant que sous-vue supplémentaire à la fenêtre. Seule la première sous-vue obtient les événements de rotation. Ce que vous pouvez faire est de l'ajouter en tant que 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];    
121
dizy

Le problème

À compter de iOS 6, seul le contrôleur de vue le plus élevé (à côté de l'objet UIApplication) participe à la décision de faire une rotation dans réponse à un changement d'orientation de l'appareil.

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

La solution

J'ai ouvert la source d'un pod nommé AGWindowView .
Il gérera automatiquement les rotations et les changements de trames afin que vous n'ayez pas à vous en préoccuper.

Le code

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

83
hfossli

J'ai créé une catégorie sur UIApplication qui possède une propriété d'assistance et une méthode pour obtenir la première sous-vue de la fenêtre keyWindow. C'est la vue que vous voulez superposer quand même. Désormais, lorsque vous ajoutez une vue gérée par 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];
4
Jon

En effet, lorsque vous mentionnez que votre vue a été ajoutée directement à UIWindow, par conséquent, lorsque la méthode de rotation est appelée pour le contrôleur de navigation, rien ne se passe dans uiview. UIView pivoterait s'il s'agissait d'une sous-vue de la vue du contrôleur de vue. Si pour une raison quelconque cela ne peut pas être fait. Ensuite, vous pouvez 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 modifiez également l'orientation de votre vue.

1
Oscar Gomez

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

0
Kristopher Johnson

Une autre solution comment j'ai résolu ce problème.

Définir l'orientation actuelle:

@interface AJImageCollectionViewController (){
    UIInterfaceOrientation _currentOrientation;
}
@end

Puis vérifiez l’orientation dans viewWillLayoutSubviews:

- (void)viewWillLayoutSubviews {
    [self checkIfOrientationChanged];
}

- (void)checkIfOrientationChanged {
    UIInterfaceOrientation newOrientation = [[UIApplication sharedApplication] statusBarOrientation];
    BOOL newOrientationIsPortrait = UIInterfaceOrientationIsPortrait(newOrientation);
    BOOL oldOrientationIsPortrait = UIInterfaceOrientationIsPortrait(_currentOrientation);

    // Check if the orientation is the same as the current
    if(newOrientationIsPortrait != oldOrientationIsPortrait){
        _currentOrientation = newOrientation;
        // Do some stuff with the new orientation
    }
}
0
Antoine