JXOrientation : simplifier la gestion des rotations du device.

JegnuXJegnuX Membre
juillet 2012 modifié dans Actualités #1
Salut à  tous.



Je vous présente une petite classe que j'ai réalisée : JXOrientation - https://github.com/JegnuX/JXOrientation



Alors à  l'origine, j'ai fais cette classe pour m'amuser un peu avec le runtime. Je n'ai donc jamais utilisé cette classe dans un projet, et je ne garanti même pas sa pertinence image/biggrin.png' class='bbc_emoticon' alt=':D' />

Mais au cas où je la partage quand même, des fois que ça donne des idées à  certains image/smile.png' class='bbc_emoticon' alt=':)' />



L'idée était de faire un sorte d'objet proxy un peu comme UIAppearance.

En gros toutes les UIView ou sous-classe d'UIView ont de nouvelles properties :


- (id) portrait;<br />
- (id) portraitStraight;<br />
- (id) portraitUpsideDown;<br />
- (id) landscape;<br />
- (id) landscapeLeft;<br />
- (id) landscapeRight;<br />




Ce sont donc des objets proxy (qui héritent de NSProxy).

On peut leur envoyer n'importe quel message que le receveur sache gérer.



Les invocations sont conservées de côté et ne seront invoquées que lors d'un changement d'orientation, dans l'ordre où elles ont été saisies.





Petit exemple :

J'ai créé mon interface portrait dans un xib, et j'ai rajouté ce code dans mon viewDidLoad :
- (void)viewDidLoad<br />
{<br />
	[super viewDidLoad];<br />
	[[orientationLabel portraitStraight] setText:@&quot;Portrait&quot;];<br />
	[[orientationLabel portraitUpsideDown] setText:@&quot;Portrait Upside Down&quot;];<br />
	[[orientationLabel landscapeLeft] setText:@&quot;Landscape Left&quot;];<br />
	[[orientationLabel landscapeRight] setText:@&quot;Landscape Right&quot;];<br />
<br />
	[[imageView portrait] setCenter:imageView.center];<br />
	[[imageView landscape] setCenter:CGPointMake(240., 160.)];<br />
  <br />
	[[textView portrait] setFrame:textView.frame];<br />
	[[textView landscape] setFrame:CGRectMake(20., CGRectGetMaxY(orientationLabel.frame), 150., 250.)];<br />
  <br />
	[[textView portrait] setBackgroundColor:[UIColor whiteColor]];<br />
	[[textView landscape] setBackgroundColor:[UIColor blackColor]];<br />
  <br />
	[[textView portrait] setTextColor:[UIColor blackColor]];<br />
	[[textView landscape] setTextColor:[UIColor whiteColor]];<br />
  <br />
	[[separatorView portrait] setHidden:NO];<br />
	[[separatorView landscape] setHidden:YES];<br />
  <br />
	[[wrapperView portrait] setFrame:wrapperView.frame];<br />
	[[wrapperView landscape] setFrame:CGRectMake(310., CGRectGetMaxY(orientationLabel.frame), 150., 150.)];<br />
}<br />




Et quand je tourne, je passe de ça :

[img]http://cl.ly/image/2W3228242J2B/Capture d'écran 2012-07-19 à %2013.36.08.png[/img]



à  ça :

[img]http://cl.ly/image/302n0n3h2W2J/Capture d'écran 2012-07-19 à %2013.36.12.png[/img]







Bon là  ça casse pas trois pattes à  un canard, mais sur une interface iPad composée de plusieurs blocs distincts mais positionné totalement différemment d'une interface à  l'autre, ça peut être intéressant.





Après, comme j'ai dit, je m'en suis encore jamais vraiment servi, c'était un peu pour m'amuser avec le runtime (on retrouve du message forwarding, du associated objects, et du method swizzling).



Je suis donc ouvert à  toutes vos remarques, critiques, idées d'amélioration etc... image/smile.png' class='bbc_emoticon' alt=':)' />
Mots clés:

Réponses

  • Eh bien je trouve ça franchement pratique !

    Vraiment bien foutu ton truc. C'est une bonne idée !
  • Effectivement! Je trouve ça vraiment génial image/smile.png' class='bbc_emoticon' alt=':)' />



    C'est une très bonne idée.
  • ça a l'air sympa comme solution bien que, mis à  part pour les frame, j'ai du mal à  voir dans quel cas je pourrai modifier d'autre attributs (genre le texte, ou un item qui devient hidden). As-tu testé en mettant des frames calculées "dynamiquement"? Car tu utilises que des magic numbers dans ton exemple, ce qui n'est pas très propre.



    Par contre je me pose une question sur l'utilisation de NSProxy. Quel est l'avantage face à  NSObject dans ce contexte précis.. juste parce que "moins lourd" ? Au départ NSProxy est surtout utile pour du IPC (Inter-Process Communication)
  • On est d'accord que le plus intéressant c'est de pouvoir modifier les frame, center, bounds et à  la limite, le transform.



    Mais au final c'était plus simple de faire comme j'ai fait de sorte à  ce que ce soit universel (dans le sens où on peut appeler ce qu'on veut), plutôt que d'implémenter chacune de ces méthodes là .



    Par exemple, on pourrait vouloir faire un "setNeedsLayout" pendant la rotation pour s'adapter. Et du coup ça fonctionne.





    Après pour les magics numbers je suis d'accord. À la base le projet iPad qui m'a donné l'idée de cette classe contenait des vues composé de plusieurs blocs dispersé et pour le coup, les "magic numbers" étaient ce qu'il y avait de plus pratique :-/



    Mais je vais essayer d'apporter une evolution qui me permettrai d'avoir des getters fonctionnels.



    À l'heure actuelle si on fait un [[view landscape] frame], bah ça va juste rien faire ni rien retourner : ça va se contenter d'appeller "frame" pendant la rotation.

    Du coup ce que je pensait faire, c'est quand on envoie un message, je check le selector, je met "set" devant et je fous une majuscule. Si je vois que la target repond à  ce nouveau selector, je considère que celui de base est un getter. À ce moment là  je récupère l'invocation du "setter", j'en récupère l'argument, et je le retourne.



    et du coup après on pourrait faire du positionnement relatif type :
    [[imageView landscapeLeft] setCenter:[[container landscapeLeft] center]];<br />
    








    Sinon, quand a l'utilisation du NSProxy, en fait pour être franc, au début j'avais fait un NSObject, puis en écrivant ce post, quand j'ai parlé de proxy je me suis souvenu qu'il existait une classe NSProxy. Et quand j'ai lu la description ça m'a semblé parfaitement adapté :
    NSProxy is an abstract superclass defining an API for objects that act as stand-ins for other objects or for objects that don't exist yet. Typically, a message to a proxy is forwarded to the real object or causes the proxy to load (or transform itself into) the real object. Subclasses of NSProxy can be used to implement transparent distributed messaging (for example, NSDistantObject) or for lazy instantiation of objects that are expensive to create.
  • Justement j'ai aussi cherché de mon côté, et concernant le forwarding, NSObject le permet aussi.

    Mais bon honnêtement dans ce cas là  l'utilisation de NSProxy ne me parait pas inadapté non plus dans le sens on tu n'as pas besoin d'un objet réel, mais juste du forwarding
  • Oui oui je sais bien que NSObject permet le forwarding. Comme dit, c'est ce que j'avais fait à  la base. C'est en écrivant le post que je me suis dis "Hum, je vais switcher sur NSProxy, ça semble fait exprès pour ce genre de cas."
Connectez-vous ou Inscrivez-vous pour répondre.