Je souhaite essentiellement que mes sous-vues soient positionnées différemment en fonction de l'orientation de l'iPad (Portrait ou Paysage) à l'aide des classes de dimensionnement introduites dans xcode 6. J'ai trouvé de nombreux tutoriels expliquant comment différentes classes de dimensionnement sont disponibles pour les Iphones en portrait et paysage sur l'IB mais cependant, il semble n'y en avoir aucun qui couvre les modes paysage ou portrait individuels pour l'iPad sur IB. Quelqu'un peut-il aider?
objective-c
ios8
size-classes
adaptive-ui
neelIVP
la source
la source
Réponses:
Il semble que l'intention d'Apple soit de traiter les deux orientations de l'iPad de la même manière - mais comme un certain nombre d'entre nous le constatent, il existe des raisons de conception très légitimes de vouloir modifier la disposition de l'interface utilisateur pour iPad Portrait par rapport à iPad Landscape.
Malheureusement, le système d'exploitation actuel ne semble pas prendre en charge cette distinction ... ce qui signifie que nous sommes de retour à la manipulation des contraintes de mise en page automatique dans le code ou des solutions de contournement similaires pour atteindre ce que nous devrions idéalement pouvoir obtenir gratuitement en utilisant l'interface utilisateur adaptative. .
Pas une solution élégante.
N'existe-t-il pas un moyen d'exploiter la magie qu'Apple a déjà intégrée à IB et UIKit pour utiliser une classe de taille de notre choix pour une orientation donnée?
~
En réfléchissant au problème de manière plus générique, j'ai réalisé que les «classes de taille» sont simplement des moyens de traiter plusieurs mises en page stockées dans IB, afin qu'elles puissent être appelées au besoin au moment de l'exécution.
En fait, une «classe de taille» n'est en réalité qu'une paire de valeurs d'énumération. Depuis UIInterface.h:
Ainsi, indépendamment de ce qu'Apple a décidé de nommer ces différentes variantes, il ne s'agit fondamentalement que d'une paire d'entiers utilisés comme identifiant unique, pour distinguer une mise en page d'une autre, stockée dans IB.
Maintenant, en supposant que nous créons une mise en page alternative (en utilisant une classe de taille inutilisée) dans IB - par exemple, pour iPad Portrait ... existe-t-il un moyen pour que l'appareil utilise notre choix de classe de taille (disposition de l'interface utilisateur) au besoin au moment de l'exécution ?
Après avoir essayé plusieurs approches différentes (moins élégantes) du problème, j'ai soupçonné qu'il pourrait y avoir un moyen de remplacer la classe de taille par défaut par programme. Et il y a (dans UIViewController.h):
Ainsi, si vous pouvez empaqueter la hiérarchie de votre contrôleur de vue en tant que contrôleur de vue `` enfant '', et l'ajouter à un contrôleur de vue parent de niveau supérieur ... alors vous pouvez conditionnellement remplacer l'enfant en pensant qu'il s'agit d'une classe de taille différente de la classe par défaut. du système d'exploitation.
Voici un exemple d'implémentation qui fait cela, dans le contrôleur de vue 'parent':
En guise de démonstration rapide pour voir si cela fonctionnait, j'ai ajouté des étiquettes personnalisées spécifiquement aux versions `` Regular / Regular '' et `` Compact / Regular '' de la disposition du contrôleur enfant dans IB:
Et voici à quoi cela ressemble en cours d'exécution, lorsque l'iPad est dans les deux orientations:
Voila! Configurations de classe de taille personnalisée au moment de l'exécution.
Espérons qu'Apple rendra cela inutile dans la prochaine version du système d'exploitation. En attendant, cela peut être une approche plus élégante et évolutive que de jouer par programme avec les contraintes de mise en page automatique ou de faire d'autres manipulations dans le code.
~
EDIT (6/4/15): Veuillez garder à l'esprit que l'exemple de code ci-dessus est essentiellement une preuve de concept pour démontrer la technique. N'hésitez pas à vous adapter au besoin à votre propre application spécifique.
~
EDIT (24/7/15): Il est gratifiant que l'explication ci-dessus semble aider à démystifier le problème. Bien que je ne l'ai pas testé, le code de mohamede1945 [ci-dessous] ressemble à une optimisation utile à des fins pratiques. N'hésitez pas à le tester et dites-nous ce que vous en pensez. (Par souci d'exhaustivité, je laisserai l'exemple de code ci-dessus tel quel.)
la source
UITraitCollection
est suffisamment optimisé etoverrideTraitCollectionForChildViewController
est appelé assez rarement pour ne pas poser de problème de vérifier la largeur et de le créer ensuite.Pour résumer la très longue réponse de RonDiamond. Tout ce que vous avez à faire est dans votre contrôleur de vue racine.
Objectif c
Rapide:
Ensuite, dans Storyborad, utilisez une largeur compacte pour Portrait et une largeur régulière pour Paysage.
la source
- (UITraitCollection *)traitCollection
au lieu deoverrideTraitCollectionForChildViewController
. Les contraintes doivent également correspondre aux collections de traits, donc wC (hAny).L'iPad a le trait de taille «régulière» pour les dimensions horizontales et verticales, ne faisant aucune distinction entre portrait et paysage.
Ces traits de taille peuvent être remplacés dans votre
UIViewController
code de sous-classe personnalisé , via la méthodetraitCollection
, par exemple:Cela donne à l'iPad les mêmes caractéristiques de taille que l'iPhone 7 Plus. Notez que les autres modèles d'iPhone ont généralement le trait de `` largeur compacte '' (plutôt que de largeur régulière) quelle que soit l'orientation.
Imiter l'iPhone 7 Plus de cette manière permet à ce modèle d'être utilisé comme substitut de l'iPad dans Interface Builder de Xcode, qui n'est pas au courant des personnalisations dans le code.
Sachez que Split View sur l'iPad peut utiliser des caractéristiques de taille différentes du fonctionnement normal en plein écran.
Cette réponse est basée sur l'approche adoptée dans ce billet de blog , avec quelques améliorations.
Mise à jour 2019-01-02: mise à jour pour corriger la barre d'état cachée intermittente dans le paysage iPad et le piétinement potentiel des (plus récents) traits dans
UITraitCollection
. Notez également que la documentation Apple recommande en fait de ne pas remplacertraitCollection
, donc à l'avenir, il peut se révéler des problèmes avec cette technique.la source
traitCollection
propriété doit être en lecture seule: developer.apple.com/documentation/uikit/uitraitenvironment/…La réponse longue et utile de RonDiamond est un bon début pour comprendre les principes, mais le code qui a fonctionné pour moi (iOS 8+) est basé sur une méthode de substitution
(UITraitCollection *)traitCollection
Donc, ajoutez des contraintes dans InterfaceBuilder avec des variations pour Width - Compact, par exemple pour la propriété de contrainte Installed. Donc Largeur - Tout sera valable pour le paysage, Largeur - Compact pour Portrait.
Pour changer les contraintes dans le code en fonction de la taille actuelle du contrôleur de vue, ajoutez simplement ce qui suit dans votre classe UIViewController:
la source
Dans quelle mesure votre mode paysage sera-t-il différent de votre mode portrait? Si c'est très différent, il peut être judicieux de créer un autre contrôleur de vue et de le charger lorsque l'appareil est en mode paysage
Par exemple
la source
Version Swift 5. Ça fonctionne bien.
la source
Code Swift 3.0 pour la solution @RonDiamond
la source