Comment faire une case réactive pour l'iPhone?

GreensourceGreensource Membre
13:19 modifié dans API UIKit #1
Bonjour, bonjour!
Je suis en train de me faire un petit projet, un jeu de plateau.
Pour celui-çi je vais avoir besoin d'un ensemble de "case" répartie sur une grille!
Je suis en train de lire de la doc à  droite à  gauche mais comme j'aime bien les gens de ce forum et que vous êtes de bon conseil je me suis dit:
"Allez on va allez leur demander si il n'aurais pas quelques petit "trucs" pour bien partir et pas se planter!" ;)

Donc me voilà ! Je vous explique vite fait ce que j'imagine. Donc je construit un espèce de widget "case" et je fait une sorte de vue perso ou je dispose mes "cases". Ensuite je lie mes cases à  mon code pour quelles réagissent. C'est un truc du genre qu'il faut faire?

Réponses

  • Philippe49Philippe49 Membre
    13:19 modifié #2
    Tu es en iPhone ? (parce que tu l'as mis dans les questions API mac)
    Sur plate-forme traditionnelle Cocoa tu as deux possibilités :
        une NSMatrix, chaque case étant un NSControl
        une vue qui teste la position du mouseDown pour réagir
    Avec iPhone, il n'y a pas de UIMatrix donc soit tu fais
        une classe perso MyUIMatrix contenant une NSArray de UIControl
        une UIView perso qui réagit selon la position du UITouch

    Sachant que la solution UIMatrix est plus gourmande pour l'iPhone, et donc moins recommandée vue la limitation technique de cette plate-forme.
  • GreensourceGreensource Membre
    13:19 modifié #3
    Oups je me suis planté de section désoler.
    Donc je vais aller voir comment fonctionne une UIView. Le truc c'est que je suis plus que débutant, je n'ai jamais rien fait de ce genre.
    Je suis entrain de chercher des tutos par ce que là  même les concepts de base j'ai beaucoup de mal.
    Tu vois je ne suis même pas très à  l'aise avec les contrôleurs.
    Je vais me plonger dans tout ça!
  • GreensourceGreensource Membre
    13:19 modifié #4
    J'avance quelques peu dans ma réflexion. Mais d'autres questions arrivent, forcément  :P
    Pour être franc avec vous, j'ai pas un super niveau d'Anglais donc j'ai un peu de souci pour bien comprendre la doc.
    Donc là  par exemple pour mes cases. J'ai fouiné un peu et je me dit que je pourrais faire que ma case hérite soit de UIControl soit de UIResponder.
    En effet ma case doit pouvoir réagir au toucher de l'utilisateur (pour la sélectionner). Du coup ça ressemble plus à  UIResponder je trouve mais je ne suis pas sur du tout dans le sens ou j'ai beaucoup plus de mal à  comprendre UIControl.

    Le problème avec UIResponder si j'ai bien compris c'est que les events sont envoyer à  une "chaine" de récepteurs, or moi je voudrais que mes cases soit toutes en même temps le firstResponder. Du coup je vois bien que ce n'est pas ça que je dois utiliser, ou bien pas comme ça en tout cas.

    Ou alors sous-classer UIControl. Mais vraiment du mal à  comprendre, je vais chercher un tuto pour voir.

    Si vous avez une idée de comment m'aider, au moins à  comprendre ça serait bien sympa de votre part. Merci beaucoup.
  • AliGatorAliGator Membre, Modérateur
    13:19 modifié #5
    Hello GreenSource

    Alors en fait il faut voir pour moi UIResponder comme une classe un peu "bas niveau", qui réceptionne les événements bruts pour les traà®ter : touchBegan, touchMoved, touchEnded. Les UIResponders sont organisés sous forme de "chaà®ne", c'est à  dire qu'il y a toujours un (et unique !!) firstResponder, qui est le premier à  essayer de traiter les événements. Il faut voir le "firstResponder" comme "l'objet qui a le focus" si tu veux.
    Par exemple sur OSX/Cocoa, le firstResponder est l'objet qui va recevoir entre autres les évnements de touche clavier, quand tu tapes une touche, donc ça peut être par exemple un champ de texte dans lequel les touches que tu tapes vont te permettre d'écrire

    Si le firstResponder ne traite pas les événements (car il n'implémente pas touchBegan etc, ou parce qu'il passe la main, etc), c'est le UIResponder suivant dans la chaà®ne des UIResponder (le "nextResponder" de l'objet firstResponder) qui essaye de répondre, et si ce nextResponder ne traite pas non plus l'événement, c'est à  son nextResponder à  lui qu'on va demander, etc... (je sais que t'es pas fan d'anglais mais c'est décrit ici dans la doc). Donc, au passage, on ne peux pas avoir "tout le monde qui est firstResponder à  la fois !

    UIResponder est plutôt une "interface" qu'une classe à  proprement parler : on ne va pas créer un UIResponder directement, on a plutôt des classes qui dérivent de UIResponder pour indiquer qu'elles savent répondre à  la gestion d'événements.

    UIControl par contre est une classe qui dérive de UIResponder, mais représente un contrôle au sens GUI du terme, comme un bouton, un slider, un champ de texte. Entre autres, UIControl sait donc répondre aux événements "bas niveau" comme touchBegan & co aussi puisqu'il dérive de UIResponder... mais rajoute aussi surtout la gestion du mécanisme target/action.




    Après pour ton cas, ça dépend ce que sont tes cases!! Des UIViews (ajoutées en subView à  une UIView parente) ? Ou ce sont tes cases hexagonales dont on parlait dans l'autre sujet, ce qui veut dire que tu as une unique UIView qui gère tout, et dessine chacune de tes cases, du coup tu n'as pas de "vue case" à  proprement parler (pas une UIView par case quoi), tes classes "cases" sont juste côté modèle pour indiquer leur position, état, valeur, etc, mais ne sont pas des UIViews ? Si c'est ce dernier cas, c'est à  la vue de gérer les événements, donc à  la vue parente de déterminer elle-même dans quelle case (côté modèle) ton "toucher" est intervenu... et ensuite appeler alors une méthode (de ton choix que tu peux appeler genre "clicked" par ex) de ta "case" que tu as déterminé être celle cliquée.

    Dans l'exemple que je t'avais filé j'avais juste fait "clickedCell.selected = YES" il me semble, où clickedCell était déterminée par une boucle dans la méthode [tt]cellAtPoint[/tt]... bah en l'occurence il suffit en gros que tu utilises le même principe, mais remplaces selected=YES par [tt][clickedCell clicked][/tt]. Et ainsi tu peux mettre le code adéquat dans la méthode clicked de tes HXCells pr traiter le cas où une cellule est cliquée...
  • GreensourceGreensource Membre
    13:19 modifié #6
    En fait je voudrais décomposé ma structure encore un peu. Si tu te rappels, avec ta méthode j'avais un pattern dans ma vue "plateau", celle qui affiche toutes les cases. Et un model de case qui, comme tu le dis contient les coordonnées des cases.
    Ca ne me conviens pas totalement car il me semble plus logique que mes cases ai non seulement un model mais aussi leur propre représentation. Donc je veux implémenter un MVC pour chaque case.

    Problème, ma vue case ne peut hériter de UIView car je ne veux surtout pas qu'elle soit rectangulaire. Mais il faut quand même qu'elle réponde au toucher. Donc je pensais la faire hériter de UIControl.
    Mais nouveau problème je ne comprend pas comment faire avec les:
    addTarget:action:forControlEvents:
    sendAction:to:forEvent:

    Je cherche des exemples depuis tout à  l'heure, dans les samples code ou bien en tuto mais rien. A chaque fois ce sont des vue qui ont utilisée et tout le mécanisme de Target-Action est du coup camouflé! :-\\

    Je voudrais argumenter un minimum, car la solution que tu m'avais donnée marchais bien. Si je veux découpler mon architecture encore un peu c'est parce que je voudrais avoir des cartes de jeu très modulaire, avec possibilité de modif en cours de jeu etc... Il me semble donc logique qu'une case ai sa propre vue.
  • GreensourceGreensource Membre
    13:19 modifié #7
    Désoler pour le double post. Bon je crois que je commence un peu mieux à  comprendre.
    Ce que j'ai fait, c'est une vue case qui hérite de UIControl, un contrôleur de vue qui hérite de NSObject et un model de case qui hérite aussi de NSObject.
    Dans mon contrôleur j'ai une méthode select: qui doit-être appelé quand on clic sur la vue hexagonale de ma case. Du coup voilà  comment j'initialise le contrôleur:
    - (id)initWithCase:(GWCase*)theCase View:(GWCaseView*)theView<br />{<br />	if(self = [super init]){<br />		// initialisation de la case<br />		myCase = theCase;<br />		myView = theView;<br />		[myView addTarget:self action:NSSelectorFromString(@&quot;select:&quot;) forControlEvents:UIControlEventAllEvents];<br />	}<br />	return self;<br />}
    

    Je vais essayer d'intégrer tout ça à  mon appli en croisant les doigts ^^. Mais déjà  je commence à  un peu mieux saisir les Control. Notamment grâce à  ce tuto
  • AliGatorAliGator Membre, Modérateur
    13:19 modifié #8
    Heu tes myCase et myView sont "assign" ? Ce serait pas mieux de faire du retain dessus ? (et release dans le dealloc évidemment) Ca éviterait des éventuels soucis
  • GreensourceGreensource Membre
    mars 2009 modifié #9
    Non je les ai mise en retain. Du coup je me suis planté dans l'init c'est ça? Je devrais mettre quoi?

    [edit] Si je comprends certain des post où l'on en a déjà  parlé je dois écrire: self.myCase : theCase. Comme celà  ça appel le setter, c'est bien ça? Qui du coup doit faire:
    <br />(void)setMyCase(GWCase*)theCase<br />{<br />    [theCase retain];<br />    myCase = theCase;<br />    [theCase release];<br />}<br />
    

    Enfin je suis pas sur du tout, je trouve ça bizarre ce que j'ai écrit. Je ne comprend pas tout disons ^^

    [edit] En effet j'ai rien compris ;-)
    Et en plus c'est écrit en gros dans la doc comment c'est fait: ici
  • AliGatorAliGator Membre, Modérateur
    13:19 modifié #10
    Oui c'est tout à  fait ça, c'est bien comme ça qu'il faut faire. Ou tu peux aussi faire le retain toi-même (puisque dans le cas du init tu sais que myCase n'est pas encore initialisé), genre [tt]myCase = [theCase retain];[/tt] en l'occurence ça revient au même (puisque myCase était à  nil lors de l'appel à  init, c'est appelé qu'à  la construction)

    Cela n'empêche pas dans tous les cas de figure, puisque ta variable d'instance myCase est de type "retain", qu'il ne faut pas oublier d'envoyer un "release" à  cette variable dans le dealloc (ou d'appeler [tt]self.myCase = nil;[/tt] ça revient au même) de ta classe.
  • GreensourceGreensource Membre
    13:19 modifié #11
    Ah ouais pas bête. J'aime mieux ça d'ailleurs, je trouve ça plus explicite que self.myCase = theCase.
    Ok pour le dealloc. Bon bas c'est cool je commence à  comprendre la gestion de la mémoire, ça fait plaisir. Merci.
Connectez-vous ou Inscrivez-vous pour répondre.