Question

Il est plus d'une question d'ordre général pour les gens me donnent des indications sur, essentiellement Im apprentissage du développement iPad / iPhone et viennent enfin à travers la question de soutien multi-orientation.

Je l'ai regardé un montant juste de Doco, et mon livre « A partir de l'iPhone 3 de développement » a un chapitre agréable là-dessus.

Mais ma question est, si je devais changer mes commandes (programatically ou même utiliser des vues différentes pour chaque orientation) sur la façon dont la terre pour les gens à maintenir leur base de code? Je ne peux imaginer tant de problèmes avec le code spaghetti / des milliers de « si » les contrôles dans tous les sens, qu'il me rendre fou de faire un petit changement à la disposition de l'interface utilisateur.

Quelqu'un at-il expérience dans le traitement de cette question? Ce qui est un bon moyen de le contrôler?

Merci beaucoup Mark

Était-ce utile?

La solution

Je le fais avec deux méthodes simples dans mon contrôleur de vue:

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

- (void) adjustViewsForOrientation:(UIInterfaceOrientation)orientation {
    if (orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight) {
        titleImageView.center = CGPointMake(235.0f, 42.0f);
        subtitleImageView.center = CGPointMake(355.0f, 70.0f);
        ...
    }
    else if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown) {
        titleImageView.center = CGPointMake(160.0f, 52.0f);
        subtitleImageView.center = CGPointMake(275.0f, 80.0f);
        ...
    }
}

Pour garder ce propre, vous pouvez facilement compartimenter la vue des ajustements / rechargeant / etc. avec des méthodes appelées à l'intérieur du conditionnel if-else unique.

Autres conseils

Cela dépend vraiment de ce que vous traçons.

Si vous regardez l'application Paramètres Apple, vous pouvez voir qu'ils utilisent des vues de table pour la mise en page, avec des cellules personnalisées pour la plupart des lignes. Avec cela, vous pouvez permettre à une interface simple de tourner assez bon marché en remplissant simplement la largeur des cellules. Cette même applique à des choses comme Mail, où il y a des cellules modifier du texte dans chaque ligne. Et les tables peuvent facilement être tous transparents, avec seulement des boutons ou des étiquettes visibles, ils ne ressemblent pas à des tables.

Vous pouvez obtenir beaucoup de milage de la autoresizingMask de chaque UIView. Si vous avez un ou plusieurs éléments qui peuvent avoir une hauteur flexible, vous pouvez généralement obtenir une mise en page d'interface qui ressemble bien en orientation. Selon la façon dont il semble, vous pouvez parfois juste tout broches vers le haut.

Dans de rares cas, si tous les éléments d'interface intègrent dans un carré, vous pouvez simplement les tourner en place.

Il y a deux moments où vous devez explicitement gérer les changements d'orientation. L'un est quand une vue de côté se déplace au-dessous de l'autre lors de la rotation. L'autre est quand vous avez des images différentes pour chaque orientation, par exemple si vous voulez toujours être pleine largeur.

Il y a parfois des façons de contourner les deux. Vous pouvez utiliser des images ou vous limiter étirables à une vue par ligne. Ou vous pouvez verrouiller l'orientation de certaines vues.

Si vous devez modifier la mise en page de vue, il existe une méthode layoutSubviews explicite. Vous devriez essayer de gérer vous tous la mise en page conditionnelle dans cette seule méthode. Il est seulement appelé lorsque les limites de changement de vue, par exemple sur la rotation ou si vous avez fait de la place pour le clavier. Faites une vue personnalisée pour chaque hiérarchie d'affichage qui doit répondre à la rotation et la disposition des sous-vues à partir de là.

Le SDK iPhone est construit autour d'avoir une architecture MVC, donc en théorie si vous gardez toute votre logique (modèle) séparé de votre interface utilisateur (vue), vous n'aurez à vous soucier de l'interface utilisateur dans un seul endroit: vos contrôleurs de vue . Pour ceux-ci, vous pourriez avoir un contrôleur de vue pour chaque orientation, dont chacun serait alors juste chargé avec un if / else pour choisir le contrôleur de vue de la charge.

La même idée est valable pour le soutien iPhone / iPad, où vous pouvez charger un autre contrôleur de vue qui peut gérer des écrans plus larges.

Je ne peux pas se porter garant pour ce code, et en toute honnêteté les willRotateToInterfaceOrientation ci-dessus fonctionne très bien. Voici une autre prise sur elle avec FBDialog.m de Facebook pour iPhone / iPad. (Bien que, je pense que ce fut une WebView)

Voici l'essentiel

[[NSNotificationCenter defaultCenter] addObserver:self
  selector:@selector(deviceOrientationDidChange:)
  name:@"UIDeviceOrientationDidChangeNotification" object:nil];


- (void)deviceOrientationDidChange:(void*)object {
  UIDeviceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
  if ([self shouldRotateToOrientation:orientation]) {


    CGFloat duration = [UIApplication sharedApplication].statusBarOrientationAnimationDuration;
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:duration];
    [self sizeToFitOrientation:YES];
    [UIView commitAnimations];
  }
}


-(CGAffineTransform)transformForOrientation {
  UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
  if (orientation == UIInterfaceOrientationLandscapeLeft) {
    return CGAffineTransformMakeRotation(M_PI*1.5);
  } else if (orientation == UIInterfaceOrientationLandscapeRight) {
    return CGAffineTransformMakeRotation(M_PI/2);
  } else if (orientation == UIInterfaceOrientationPortraitUpsideDown) {
    return CGAffineTransformMakeRotation(-M_PI);
  } else {
    return CGAffineTransformIdentity;
  }
}

- (void)sizeToFitOrientation:(BOOL)transform {
  if (transform) {
    self.transform = CGAffineTransformIdentity;
  }

  CGRect frame = [UIScreen mainScreen].applicationFrame;
  CGPoint center = CGPointMake(
    frame.origin.x + ceil(frame.size.width/2),
    frame.origin.y + ceil(frame.size.height/2));

  CGFloat scale_factor = 1.0f;
  if (FBIsDeviceIPad()) {
    // On the iPad the dialog's dimensions should only be 60% of the screen's
    scale_factor = 0.6f;
  }

  CGFloat width = floor(scale_factor * frame.size.width) - kPadding * 2;
  CGFloat height = floor(scale_factor * frame.size.height) - kPadding * 2;

  _orientation = [UIApplication sharedApplication].statusBarOrientation;
  if (UIInterfaceOrientationIsLandscape(_orientation)) {
    self.frame = CGRectMake(kPadding, kPadding, height, width);
  } else {
    self.frame = CGRectMake(kPadding, kPadding, width, height);
  }
  self.center = center;

  if (transform) {
    self.transform = [self transformForOrientation];
  }
}

Dans votre question, vous avez écrit:

  

Je ne peux imaginer tant de problèmes avec le code spaghetti / des milliers de « si » vérifie tous les sens, qu'il me rendre fou de faire un petit changement à la disposition de l'interface utilisateur.

Une façon d'esquiver est de faire une hiérarchie de vue qui sépare le traitement des changements spécifiques iPhone / iPad à partir du début. Vous souhaitez ne devez définir quelle vue est d'abord chargé pour chaque appareil. Ensuite, vous créez un viewcontroller comme vous le faites normalement, mais vous aussi sous-classe la viewcontroller que vous avez créé. Une sous-classe pour chaque appareil. C'est là que vous pouvez mettre le code spécifique de l'appareil, comme la manipulation d'orientation. Comme ceci:

MyViewController.h            // Code that is used on both devices
    MyViewController_iPhone.h // iPhone specific code, like orientation handling
    MyViewController_iPad.h   // iPad specific code, like orientation handling

Si vous êtes intéressé par cette approche, je vous suggère que vous avez lu

scroll top