Mon application est destinée uniquement au périphérique iphone
(iphone 4 et 5) et conçue pour prendre en charge uniquement le système ios 6
.
Toute mon application ne supporte que le mode portrait
. Mais il existe une vue appelée "ChatView
", que je souhaite prendre en charge à la fois avec les modes landscape
et portrait
.
J'ai défini les rotations de périphérique requises comme suit -
J'ai aussi essayé de suivre le code pour supporter la rotation dans "ChatView" -
-(BOOL)shouldAutorotate
{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
Mais il ne pouvait pas faire pivoter cette vue.
J'ai beaucoup cherché, mais je ne pouvais pas trouver la solution à mon problème.
Et aussi dans "ChatView", il y a des objets comme des boutons, des champs de texte dont les cadres sont définis par programme. Donc, je veux savoir si je dois aussi définir des cadres de tous ces objets pour le mode paysage?
Aidez-moi, s'il vous plaît.
Merci.....
Je pense que si vous voulez prendre en charge une seule rotation de contrôleur de vue, ce n’est pas possible car l’application suivra les orientations que vous avez définies dans .plist
fichier. Une autre solution consiste à prendre en charge votre application pour les paysages et les portraits, et geler toutes les rotations des contrôleurs de vues en portrait, à l'exception de l'affichage Chat.
EDIT
Pour sous-classer UINavigationController
, créez un nouveau fichier avec le nom, par exemple. CustomNavigationController
et en faire une sous-classe de UINavigationController
.
fichier. h
#import <UIKit/UIKit.h>
@interface CustomNavigationController : UINavigationController
@end
fichier .m
#import "CustomNavigationController.h"
@interface CustomNavigationController ()
@end
@implementation CustomNavigationController
-(BOOL)shouldAutorotate
{
return NO;
}
-(UIInterfaceOrientationMask)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return UIInterfaceOrientationIsPortrait(interfaceOrientation);
}
@end
Définissez la classe de votre UINavigationController
dans votre classe principale xib comme CustomNavigationController
. J'espère que ça vous aide ..
Simple mais ça marche très bien. IOS 7.1 et 8
AppDelegate.h
@property () BOOL restrictRotation;
AppDelegate.m
-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if(self.restrictRotation)
return UIInterfaceOrientationMaskPortrait;
else
return UIInterfaceOrientationMaskAll;
}
ViewController
-(void) restrictRotation:(BOOL) restriction
{
AppDelegate* appDelegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
appDelegate.restrictRotation = restriction;
}
viewDidLoad
[self restrictRotation:YES]; or NO
Votre contrôleur de vue ne pivotera jamais vers une position non prise en charge par l'application elle-même. Vous devez activer toutes les rotations possibles, puis, dans la vue, les contrôleurs qui ne sont pas censés faire la rotation mettent les lignes suivantes
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
Dans ChatView, cela devrait être:
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
Si vous devez modifier votre mise en page après une rotation, vous devez implémenter les modifications appropriées dans vos sous-vues.
- (void)viewWillLayoutSubviews
Utilisation self.view.bounds
pour vérifier la taille actuelle du view
, puisque self.view.frame
ne change pas après les rotations.
pour le viewcontroller.m
spécifique que vous voulez faire pivoter
ajoutez cette méthode:
- (BOOL)canAutoRotate
{
return YES;
}
puis dans votre AppDelegate.m
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
UIViewController *currentViewController = [self topViewController];
if ([currentViewController respondsToSelector:@selector(canAutoRotate)]) {
NSMethodSignature *signature = [currentViewController methodSignatureForSelector:@selector(canAutoRotate)];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setSelector:@selector(canAutoRotate)];
[invocation setTarget:currentViewController];
[invocation invoke];
BOOL canAutorotate = NO;
[invocation getReturnValue:&canAutorotate];
if (canAutorotate) {
return UIInterfaceOrientationMaskAll;
}
}
return UIInterfaceOrientationMaskPortrait;
}
- (UIViewController *)topViewController
{
return [self topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}
- (UIViewController *)topViewControllerWithRootViewController:(UIViewController *)rootViewController
{
if ([rootViewController isKindOfClass:[UITabBarController class]]) {
UITabBarController* tabBarController = (UITabBarController*)rootViewController;
return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];
} else if ([rootViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController* navigationController = (UINavigationController*)rootViewController;
return [self topViewControllerWithRootViewController:navigationController.visibleViewController];
} else if (rootViewController.presentedViewController) {
UIViewController* presentedViewController = rootViewController.presentedViewController;
return [self topViewControllerWithRootViewController:presentedViewController];
} else {
return rootViewController;
}
}
La réponse de Ted fonctionne bien avec le problème mentionné par Alexander de Norvège. Mais je me suis dit que le problème ne se produisait pas comme l'expliquait Alexander
Lorsque ViewController B qui est actuellement en mode paysage (toutes les orientations activées) revient à ViewController A (portrait uniquement) après que l'utilisateur a cliqué sur le bouton Précédent, supportedInterfaceOrientationsForWindow n'est pas appelé et ViewController A se termine en paysage
En fait, lorsque ViewController B qui est actuellement en mode paysage (toutes les orientations activées) revient à ViewController A (Portrait uniquement) après que l'utilisateur a cliqué sur le bouton Précédent, Appdelegate
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation;
se fait appeler. Cependant, le contrôleur de vue racine est toujours ViewController B (ce contrôleur de vue activé par rotation), ViewController A ne revient pas à l'orientation portrait, puisque ViewController B renvoie toujours
-(BOOL)shouldAutorotate{
return YES;
}
Ainsi, lorsque vous appuierez sur le bouton Retour pour revenir à l'affichage, "shouldAutorotate -> NO" dans ViewController B. Ensuite, ViewController A passera en orientation Portrait. C'est ce que j'ai fait
@property (nonatomic, assign) BOOL canAutoRotate;
#pragma mark - Public methods
- (BOOL)canAutoRotate
{
return _canAutoRotate;
}
#pragma mark - Button actions
- (void)backButtonPressed:(UIButton *)sender {
_canAutoRotate = NO;
(...)
}
#pragma mark - Init
- (id)init{
if(self=[super init]) {
_canAutoRotate = YES;
}
return self;
}
Swift 3 Version cachère
J'ai laissé cela ici juste pour un cas, quelqu'un a le problème.
documentation d'Apple pour supportedInterfaceOrientations
dit:
Lorsque l'utilisateur modifie l'orientation du périphérique, le système appelle cette méthode sur le contrôleur de vue racine ou sur le contrôleur de vue présenté supérieur remplissant la fenêtre. Si le contrôleur de vue prend en charge la nouvelle orientation, la fenêtre et le contrôleur de vue sont tournés vers la nouvelle orientation. Cette méthode n'est appelée que si la méthode shouldAutorotate du contrôleur de vue renvoie la valeur true.
En quelques mots, vous devez remplacer supportedInterfaceOrientations
dans le contrôleur de vue racine afin qu'il renvoie la valeur de son contrôleur de vue enfant supérieur et la valeur par défaut sinon.
Ce que vous devez faire est de vérifier si l'application prend en charge tous les modes (voir Informations de déploiement dans les paramètres généraux des cibles ou Info.plist), recherchez la classe de votre contrôleur de vue racine. Cela peut être générique UIViewController, UINavigationController, UITabBarController ou une classe personnalisée. Vous pouvez le vérifier de cette façon:
dump(UIApplication.shared.keyWindow?.rootViewController)
Ou de toute autre manière que vous aimez.
Soit CustomNavigationController
. Donc, vous devriez écraser supportedInterfaceOrientations
comme ceci:
class CustomNavigationController: UINavigationController {
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return topViewController?.supportedInterfaceOrientations ?? .allButUpsideDown
}
}
Dans tout contrôleur de vue qui ne devrait supporter que l'orientation portrait, par exemple, remplacez supportedInterfaceOrientations
de cette façon:
class ChildViewController: UIViewController {
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .portrait
}
}
Ensuite, n'oubliez pas de vérifier si shouldAutorotate
de votre contrôleur de vue racine et du contrôleur de vue présenté supérieur renvoie déjà true
. Sinon, ajoutez ceci aux définitions de classes:
override var shouldAutorotate: Bool {
return true
}
Sinon, supportedInterfaceOrientations
ne sera jamais appelé.
Voici!
Si vous devez résoudre le problème inverse lorsqu'un seul contrôleur de vue doit prendre en charge un ensemble d'orientations et que d'autres ne le font pas, modifiez cette modification pour tous les contrôleurs de vue, sauf celui-ci.
J'espère que cela aidera.
Je ne suis pas sûr de l'historique de ce problème (maintenant = échéancier iOS 10), mais la solution la plus simple manquait car j'ai posté ceci en octobre 2016.
En supposant que vous vouliez ceci:
UINavigationController
s dans les XIBs/NIBs/Storyboards sans rien leur faire... alors (IMO) la solution la plus simple consiste à créer un UINavigationControllerDelegate, PAS la sous-classe UINavigationController (qui viole l'hypothèse 4 ci-dessus).
Quand j'ai résolu ceci, j'ai décidé de faire mon premier ViewController
un UINavigationControllerDelegate
. Ce contrôleur de vue se définit lui-même comme délégué du contrôleur de navigation et renvoie les orientations autorisées. Dans mon cas, la valeur par défaut est que toutes les orientations sont autorisées, avec portrait préféré, mais dans un cas particulier, seul le portrait est autorisé. Le code ci-dessous provient de Swift 3/XCode 8:
class iPhoneStartViewController: UIViewController {
var navInterfaceOrientationMask: UIInterfaceOrientationMask?
var navInterfaceOrientationPreferred: UIInterfaceOrientation! = .portrait
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.delegate = self
}
@IBAction func cameraButtonPressed(_ sender: AnyObject) {
if PermissionsHelper.singleton().photosPermissionGranted() == false {
self.navInterfaceOrientationMask = nil // default is: all orientations supported
self.performSegue(withIdentifier: "segueToPhotoAccess", sender: self)
} else {
self.navInterfaceOrientationMask = .portrait // this stops the next view controller from being to rotate away from portrait
self.performSegue(withIdentifier: "segueToCamera", sender: self)
}
}
}
// lock orientation to portrait in certain cases only. Default is: all orientations supported
extension iPhoneStartViewController : UINavigationControllerDelegate {
public func navigationControllerSupportedInterfaceOrientations(_ navigationController: UINavigationController) -> UIInterfaceOrientationMask {
if let mask = self.navInterfaceOrientationMask {
return mask
} else {
return .all
}
}
public func navigationControllerPreferredInterfaceOrientationForPresentation(_ navigationController: UINavigationController) -> UIInterfaceOrientation {
return self.navInterfaceOrientationPreferred
}
}
faire une sous-classe de UINavigationController comme ceci:
MyNavigationController.h
#import <UIKit/UIKit.h>
@interface MyNavigationController : UINavigationController
@end
MyNavigationController.m
#import "MyNavigationController.h"
#import "ServicesVC.h"
@implementation MyNavigationController
-(BOOL)shouldAutorotate{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations{
if ([[self.viewControllers lastObject] isKindOfClass:[ServicesVC class]]) {
return UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight;
}
return UIInterfaceOrientationMaskAll;
}
@end
en supposant que votre contrôleur de vue s'appelle: ServicesVC
Sur la base de la réponse de @iAnum, j'ai activé la détection de classe autorotate et UIViewController.
En effet, sinon, la transition vers le "contrôleur de vue spécial" et hors de celui-ci ne sera pas corrigée en orientation portrait et vous serez bloqué dans une orientation non prise en charge.
Une seule vue prenant en charge le paysage, je l'ai simplement codée en dur dans le contrôleur de vue de navigation personnalisé:
-(BOOL)shouldAutorotate
{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations
{
//Access the current top object.
UIViewController *viewController = [self.viewControllers lastObject];
//Is it one of the landscape supported ones?
if ([viewController isMemberOfClass:[SpecialViewController class]]) {
return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight;
} else
return UIInterfaceOrientationMaskPortrait;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
//Access the current top object.
UIViewController *viewController = [self.viewControllers lastObject];
//Is it one of the landscape supported ones?
if ([viewController isMemberOfClass:[SpecialViewController class]]) {
return interfaceOrientation;
} else
return UIInterfaceOrientationIsPortrait(interfaceOrientation);
}
Il y a un problème avec les VCs dont il est question ici https://stackoverflow.com/a/15057537/127735 où le fait d'appuyer en arrière dans le paysage n'appelle même pas les méthodes d'orientation, vous devez donc le pirater un peu en montrant et en écartant une vue modale.
Et rappelez-vous simplement que si vous voulez que willShowViewController se déclenche, vous devez définir self.delegate = self et ajouter UINavigationControllerDelegate à votre contrôleur de navigation personnalisé avec le code ci-dessous.
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
UIApplication* application = [UIApplication sharedApplication];
if (application.statusBarOrientation != UIInterfaceOrientationPortrait)
{
UIViewController *c = [[UIViewController alloc]init];
[c.view setBackgroundColor:[UIColor clearColor]];
[navigationController presentViewController:c animated:NO completion:^{
[self dismissViewControllerAnimated:YES completion:^{
}];
}];
}
}
Voici la réponse d'Alexandre ( https://stackoverflow.com/posts/25507963/revisions ) dans Swift:
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int {
var currentViewController: UIViewController? = self.topViewController()
if currentViewController != nil && currentViewController!.canAutoRotate() {
return Int(UIInterfaceOrientationMask.All.rawValue)
}
return Int(UIInterfaceOrientationMask.Portrait.rawValue)
}
func topViewController() -> UIViewController? {
if UIApplication.sharedApplication().keyWindow != nil
{
return self.topViewControllerWithRootViewController(UIApplication.sharedApplication().keyWindow!.rootViewController!)
}
return nil
}
func topViewControllerWithRootViewController(rootViewController: UIViewController?) -> UIViewController? {
if rootViewController == nil {
return nil
}
if rootViewController!.isKindOfClass(UITabBarController) {
var tabBarController: UITabBarController = (rootViewController as? UITabBarController)!
return self.topViewControllerWithRootViewController(tabBarController.selectedViewController)
}
else {
if rootViewController!.isKindOfClass(UINavigationController) {
var navigationController: UINavigationController = (rootViewController as? UINavigationController)!
return self.topViewControllerWithRootViewController(navigationController.visibleViewController)
}
else {
if (rootViewController!.presentedViewController != nil) {
var presentedViewController: UIViewController = rootViewController!.presentedViewController!
return self.topViewControllerWithRootViewController(presentedViewController)
}
else {
return rootViewController
}
}
}
}
En outre, vous devrez ajouter l'extrait suivant dans AppDelegate.Swift:
extension UIViewController {
func canAutoRotate() -> Bool {
return false
}}
Et pour les ViewControllers pour lesquels vous voulez autoriser toutes les rotations, ajoutez cette fonction:
override func canAutoRotate() -> Bool {
return true
}
// colle cette méthode dans la classe app Deligate
- (UIInterfaceOrientationMask)application:(UIApplication )application supportedInterfaceOrientationsForWindow:(UIWindow )window
{
if ([self.window.rootViewController.presentedViewController isKindOfClass: [_moviePlayerController class]])
{
if (self.window.rootViewController.presentedViewController)
return UIInterfaceOrientationMaskAll;
else return UIInterfaceOrientationMaskPortrait;
}
else return UIInterfaceOrientationMaskPortrait;
}
Si l'application prend en charge de IOS7 à IOS9, utilisez ce code pour l'orientation:
#if __IPHONE_OS_VERSION_MAX_ALLOWED < 90000
- (NSUInteger)supportedInterfaceOrientations
#else
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
#endif
{
if([AppDelegate isPad]) return UIInterfaceOrientationMaskAll;
else return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown;
}
Je sais que cette question est très ancienne mais qu’elle nécessite une réponse à jour. La manière la plus simple et la plus correcte d’atteindre ce résultat consiste à activer Portrait et Paysage dans les paramètres de votre application. Ajoutez ensuite ce code au délégué de votre application:
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
if let navigationController = self.window?.rootViewController as? UINavigationController {
if navigationController.visibleViewController is INSERTYOURVIEWCONTROLLERHERE {
return UIInterfaceOrientationMask.All
}
else {
return UIInterfaceOrientationMask.Portrait
}
}
return UIInterfaceOrientationMask.Portrait
}
N'oubliez pas de remplacer "INSERTYOURVIEWCONTROLLERHERE" par votre contrôleur de vue.
J'ai eu la même situation. J'ai donc subdivisé UINavigationController en CustomNavigationController, et à l'intérieur de ce CustomNavigationController, j'ai écrit:
#define IOS_OLDER_THAN_6 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] < 6.0 )
#define IOS_NEWER_OR_EQUAL_TO_6 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] >= 6.0 )
#pragma mark - Rotation
#ifdef IOS_OLDER_THAN_6
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
return (toInterfaceOrientation == UIInterfaceOrientationPortrait);
}
#endif
#ifdef IOS_NEWER_OR_EQUAL_TO_6
-(BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;;
}
#endif
J'ai utilisé ce CustomNavigationController au lieu de NavigationController existant.
Ensuite, dans le contrôleur de vue que vous devez afficher dans LandScape Orientation, dites LandScapeView, j’ai écrit
#pragma mark - Rotation
#ifdef IOS_OLDER_THAN_6
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
return (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight | toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}
#endif
#ifdef IOS_NEWER_OR_EQUAL_TO_6
-(BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskLandscapeLeft;
}
#endif
À l'intérieur de CustomNavigationController, j'ai présenté ce contrôleur de vue, non poussé dans Navigation Stack. Ainsi, LandScapeView est apparu dans LandScape Orientation.
LandScapeView *graph = [[LandScapeView alloc]init....];
[self presentViewController:graph animated:YES completion:nil];
Je n'ai rien changé dans le Orientation d'interface prise en charge dans les paramètres du projet.