Question Dispositions iOS alternatives pour portrait et paysage en utilisant un seul fichier .xib


En utilisant le générateur d'interface dans xcode et un seul fichier .xib, comment puis-je créer des mises en page alternatives lors de la rotation entre les orientations paysage et portrait?

Voir le schéma des différentes dispositions enter image description here

N.b. la vue / zone verte contiendrait 3 éléments circulant horizontalement dans le paysage et en portrait ces 3 éléments s'écouleraient verticalement dans la vue / zone verte.


38
2017-09-03 15:02


origine


Réponses:


Pour ce faire, vous pouvez avoir trois vues dans votre fichier .xib. Le premier est la vue normale de votre Viewcontroller sans sous-vues.

Ensuite, vous créez les vues pour le portrait et le paysage lorsque vous en avez besoin. Les trois doivent être des vues de niveau racine (voir la capture d'écran)

enter image description here

Dans votre Viewcontroller, créez 2 IBOutlets, un pour le portrait et un pour la vue paysage, et connectez-les avec les vues correspondantes dans le générateur d'interface:

IBOutlet UIView *_portraitView;
IBOutlet UIView *_landscapeView;
UIView *_currentView;

La troisième vue, _currentView est nécessaire pour garder une trace de l’une de ces vues actuellement affichée. Ensuite, créez une nouvelle fonction comme celle-ci:

-(void)setUpViewForOrientation:(UIInterfaceOrientation)orientation
{
    [_currentView removeFromSuperview];
    if(UIInterfaceOrientationIsLandscape(orientation))
    {
        [self.view addSubview:_landscapeView];
        _currentView = _landscapeView;
    }
    else
    {
        [self.view addSubview:_portraitView];
        _currentView = _portraitView;
    }
}

Vous devrez appeler cette fonction à deux endroits différents, d’abord pour l’initialisation:

-(void)viewDidLoad
{
    [super viewDidLoad];
    UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
    [self setUpViewForOrientation:interfaceOrientation];
}

Et deuxièmement pour les changements d'orientation:

-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    [self setUpViewForOrientation:toInterfaceOrientation];
}

Espérons que cela vous aide!


43
2017-09-12 14:36



Il n'y a pas de moyen automatique pour le supporter car il est contraire à la conception d'Apple. Vous devriez avoir un ViewController prenant en charge les deux orientations.

Mais si vous voulez vraiment le faire, vous devez recharger les événements de rotation de xib et charger différents fichiers nib.

-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    [[NSBundle mainBundle] loadNibNamed:[self nibNameForInterfaceOrientation:toInterfaceOrientation] owner:self options:nil];
    [self viewDidLoad];
}

- (NSString*) nibNameForInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    NSString *postfix = (UIInterfaceOrientationIsLandscape(interfaceOrientation)) ? @"portrait" : @"landscape";
    return [NSString stringWithFormat:@"%@-%@", NSStringFromClass([self class]), postfix];
}

Et vous créez deux fichiers nib post-corrigés avec "paysage" et "portrait".


14
2017-09-10 11:52



J'aime la solution de @ MeXx, mais elle évite de garder en mémoire deux hiérarchies de vues différentes. De plus, si une sous-vue a un état (par exemple, une couleur) qui change, vous devrez le mapper lorsque vous changez de hiérarchie.

Une autre solution pourrait consister à utiliser la mise en page automatique et à échanger les contraintes pour chaque sous-vue pour chaque orientation. Cela fonctionnerait mieux si vous établissiez une correspondance 1: 1 entre les sous-vues dans les deux orientations.

Naturellement, vous voulez utiliser IB pour définir visuellement la disposition de chaque orientation. Dans mon plan, vous devez faire ce que @MeXx prescrit, mais ensuite créer un mécanisme pour stocker les deux ensembles de contraintes une fois le nib chargé (awakeFromNib) et ré-appliquer le jeu correct sur la mise en page (viewWillLayoutSubviews). Vous pouvez jeter la hiérarchie de la vue secondaire une fois que vous avez gratté et stocké ses contraintes. (Étant donné que les contraintes sont spécifiques à une vue, vous créerez probablement de nouvelles contraintes à appliquer aux sous-vues réelles).

Désolé je n'ai pas de code. C'est juste un plan à ce stade.

Note finale - tout cela serait plus facile avec un xib qu'avec un storyboard car dans un storyboard, il est difficile de décrire des vues qui ne sont pas visibles dans la vue principale d'un contrôleur de vue (ce qui est souhaitable car autrement, un PITA à éditer). Blach!


8
2017-09-13 20:48



Vous pouvez bien sûr monsieur ....

J'ai l'habitude de faire est en donnant un cadre manuellement lorsque l'appareil tourne

Chaque fois que l'appareil tourne, - (void)viewWillLayoutSubviews se faire appeler

par exemple - prendre un UIButton *button dans ton UIView,

- (void)viewWillLayoutSubviews
   {
       if (UIDeviceOrientationIsLandscape([self.view interfaceOrientation]))
       {
         //x,y as you want
         [ button setFrame:CGRectMake:(x,y,button.width,button.height)];

       }
       else
       {
         //In potrait
          //x,y as you want
         [ button setFrame:CGRectMake:(x,y,button.width,button.height)];


       }

   }

De cette façon, vous pouvez le placer comme vous le souhaitez. Merci

S'il vous plaît jeter un oeil sur ces images

Première image de mon xCode XIB UIView que je veux dans les deux écrans

enter image description here

Maintenant que je veux regarder cette vue dans le paysage aussi je suis allé éditer mon -(void)viewWillLayoutSubviews

enter image description here

Maintenant, le résultat est comme ceci Première image de l'écran Potrait dans Simulator

enter image description here

et c'est dans le paysage

enter image description here


3
2017-09-16 17:43



Solution avec storyboard [ios7]. À l’intérieur du contrôleur de la vue principale, la vue du conteneur peut inclure le contrôleur de la barre d’onglet. À l'intérieur du contrôleur de la barre d'onglets, il y a 2 onglets. Un onglet est pour le contrôleur avec portrait et un autre pour le contrôleur en mode paysage.

Le contrôleur de vue principale implémente ces fonctions:

#define INTERFACE_ORIENTATION() ([[UIApplication sharedApplication]statusBarOrientation])

@interface MainViewController ()
@property(nonatomic,weak) UITabBarController *embeddedTabBarController;
@end

@implementation MainViewController
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:@"embedContainer"])
    {
        self.embeddedTabBarController = segue.destinationViewController;
        [self.embeddedTabBarController.tabBar setHidden:YES];
    }
}

- (void) adaptToOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    if (UIInterfaceOrientationIsLandscape(interfaceOrientation))
    {
        [self.embeddedTabBarController setSelectedIndex:1];
    }
    else
    {
        [self.embeddedTabBarController setSelectedIndex:0];
    }
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
{
    [self adaptToOrientation:interfaceOrientation];    
}

- (void) viewWillAppear:(BOOL)animated
{
    [self adaptToOrientation:INTERFACE_ORIENTATION()];
}

Le lien segue dans le storyboard doit être nommé "embedContainer".

Assurez-vous que la vue du conteneur est redimensionnable pour remplir la vue parente, dans les deux cas, paysage et portrait.

Faites attention au fait que dans le runtime 2 instances du même contrôleur vivent dans le même temps.

Storyboard


Mettre à jour: Documents Apple pour un contrôleur de vue paysage alternatif


2
2018-01-30 23:58



Je voudrais juste ajouter une nouvelle réponse pour refléter les nouvelles fonctionnalités à venir dans ios8 et XCode 6.

Dans le dernier logiciel, Apple a introduit classes de taille, qui permettent au storyboard de s’adapter intelligemment en fonction de la taille de l’écran et de l’orientation que vous utilisez. Bien que je vous suggère de regarder les documents ci-dessus ou la session 2014 de la WWDC créer des applications adaptatives avec UIKit, Je vais essayer de paraphraser.

S'assurer que les classes de taille sont activée,.

Vous remarquerez que vos fichiers de storyboard sont maintenant carrés. Vous pouvez configurer l'interface de base ici. L'interface sera redimensionnée intelligemment pour tous les périphériques activés et leur orientation.

Au bas de l'écran, vous verrez un bouton indiquant yAny xAny. En cliquant dessus, vous pouvez modifier une seule classe de taille, par exemple, paysage et portrait.

Je vous suggère de lire les documents ci-dessus, mais j'espère que cela vous aidera, car il n'utilise qu'un seul storyboard.


2
2017-08-29 13:18



Vous pouvez utiliser la bibliothèque GPOrientation. Voici lien 


1
2017-09-13 10:48



Redimensionner par programmation

J'ai une application où j'ai exactement la même situation. Dans mon NIB, je me suis contenté de la mise en page de portrait. L'autre mise en page est effectuée par programmation. Il n'est pas si difficile de spécifier quelques tailles par programme, donc pas besoin de maintenir deux NIB.

Notez que la modification de la vue par programmation en définissant des cadres entraînera une animation (ou peut facilement être réalisée à l'aide d'une animation). Cela donnera à l'utilisateur une rétroaction précieuse sur le composant déplacé vers quelle position. Si vous chargez simplement une seconde vue, vous perdrez cet avantage et du point de vue de l'interface utilisateur, je pense que le chargement d'une vue alternative n'est pas une bonne solution.

Utilisez deux contrôleurs ViewController

Si vous souhaitez utiliser deux contrôleurs ViewController, Apple vous explique comment le faire dans sa documentation de développeur, à savoir que vous trouverez la réponse à votre question ici: Répondre àOrientationChangements.

Si vous aimez le faire par programmation, vous pouvez ajouter un code de repositionnement dans la méthode didRotateFromInterfaceOrientation.

Exemple

J'ai ajouté la méthode à mon ViewController:

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
    [self adjustLayoutToOrientation];
}

Ensuite, implémenté l'ajustement de la mise en page. Voici un exemple (le code est spécifique à mon application, mais vous pouvez lire les tailles des supervisions et en calculer les cadres).

- (void)adjustLayoutToOrientation
{
    UIInterfaceOrientation toInterfaceOrientation = self.interfaceOrientation;
    bool isIPhone = !([[UIDevice currentDevice] respondsToSelector:@selector(userInterfaceIdiom)] && [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad);

    [self adjustViewHeight];
    [self adjustSubviewsToFrame: [mailTemplateBody.superview.superview frame]];

    CGRect pickerViewWrapperFrame = pickerViewWrapper.frame;
    if(isIPhone) {
        pickerViewWrapperFrame.origin.x = 0;
        pickerViewWrapperFrame.size.height = keyboardHeight;
        pickerViewWrapperFrame.origin.y = [self view].frame.size.height-pickerViewWrapperFrame.size.height;
        pickerViewWrapperFrame.size.width = [self view].frame.size.width;
    }
    else {
        pickerViewWrapperFrame = pickerView.frame;
    }

// MORE ADJUSTMENTS HERE

}

1
2017-09-16 20:44