Texte avec mots sélectionnable

tazkeoxtazkeox Membre
04:21 modifié dans Vos applications #1
Bonjour,

Je suis entrain de développement une application iPad contenant des Quizz et j'ai un problème sur la façon de développer un type d'exercice.

J'aimerai afficher un texte et rendre chacun des mots contenus dedans sélectionnable. Le but de l'exercice est que l'utilisateur identifie les mots erronées dans le texte en cliquant dessus (un second click annulerait la sélection) et lorsque l'exercice se termine l'ensemble des mots sélectionnés est récupéré et comparé à  une base de réponses correctes afin de valider ou non le succès.

J'aurai en entrée une NSString avec le texte souhaité (qui est variable bien entendue) et un NSArray contenant chaque réponse (mot erroné) sous forme de NSString.

Je pensais donc éventuellement parser le texte en entrée et de transformer chaque mot en bouton (prenant comme titlelabel la valeur du mot) et d'afficher ces boutons à  la suite de manière à  faire croire à  un texte. Es-ce la bonne solution ? Si non, laquelle me conseillerez-vous ? Si oui comment afficher ces boutons de manière à  faire penser à  un texte ?

Je précise que je suis un développeur avec plusieurs expériences mais essentiellement les bases...

Merci beaucoup.

Amicalement,
tazkeox.

Réponses

  • BunoBuno Membre
    04:21 modifié #2
    Yop,
    L'idée des boutons me semble pas mal.
  • 04:21 modifié #3
    Regarde plutôt la classe de Aligator "OHAttributedLabel", il te permettrait d'afficher du richText et, entre autre, de coller des liens pour des mots spécifiques. À toi d'utiliser ces liens comme il faut.
    Je donne une piste comme ça, parce que ça me semble l'idée la plus rapide à  mettre en place
  • AliGatorAliGator Membre, Modérateur
    04:21 modifié #4
    Oui ma classe peut sans doute te permettre de faire ce que tu veux. Sauf que bon après mettre un lien (customLink) sur *chaque* mot de ton texte de OHAttributedLabel ça peut être fastidieux... mais bon
  • DrakenDraken Membre
    04:21 modifié #5
    Si je devais faire une application comme celle-ci, je n'utiliserais pas des boutons, mais plutôt un découpage du texte.

    L'idée est de récupérer la liste de tous les mots du texte, afin de calculer leurs positions d'affichage. Le code suivant te montre comment créer un tableau de mots à  partir du texte.

    <br />// CREATION LISTE DE MOTS<br />NSArray *listeMots = [texte componentsSeparatedByString:@&quot; &quot;];<br />
    


    Il suffit ensuite de faire une boucle pour traiter chaque mot.

    NSInteger nbMots = [listeMots count];<br />for (NSInteger n=0; n&lt;nbMots; n++)<br />{<br />&nbsp;  NSString *mot = [listeMots objectAtIndex:n];<br />&nbsp;  // Traitement mot<br />&nbsp;  ....<br />}<br />
    


    La méthode sizeWithFont permet de connaà®tre la taille du rectangle graphique nécessaire à  l'affichage d'un NSString.

    CGSize taille = [mot sizeWithFont:font];
    CGFloat largeur = taille.width;
    CGFloat hauteur = taille.height;

    Le calcul nécessite de connaà®tre la police de caractère utilisée pour l'affichage. Un texte en "Arial corps 12" n'aura pas la même taille qu'en "Times Bold corps 32".

    Tu peux utiliser cette technique pour calculer le rectangle graphique occupé par chaque mot. Il ne reste ensuite plus qu'à  stocker les coordonnées des "mauvais mots" dans un tableau de CGRect.

    Pour détecter la sélection d'un "mauvais mot", il suffit juste de comparer la position de Touch avec la liste des CGRect stockés en mémoire.

    Tu peux également matérialiser la sélection d'un mot en changeant sa couleur d'affichage.

    // AFFICHAGE D&#039;UN NSSTRING SUR L&#039;ECRAN<br />[mot drawAtPoint:position withFont:font];<br />
    


    Je ne t'ai pas donné le code complet, juste des pistes pour t'orienter dans la bonne direction.

  • AliGatorAliGator Membre, Modérateur
    04:21 modifié #6
    Oui je préconise la solution que donne Draken, car en fait ma classe OHAttributedText est plutôt ciblée pour avoir un label combinant plusieurs styles (texte enrichi) en utilisant CoreText. Mais pour ton cas il sera plus simple d'utiliser UIKit vu que tu n'as pas besoin des fonctionnalités de CoreText.
  • muqaddarmuqaddar Administrateur
    04:21 modifié #7
    dans 1307626101:

    Oui je préconise la solution que donne Draken


    ça fait 2 fois !!! Il va avoir les chevilles qui enflent !
  • DrakenDraken Membre
    04:21 modifié #8
      <3 8--)
  • tazkeoxtazkeox Membre
    04:21 modifié #9
    Merci à  tous pour vos réponses.

    N'ayant vu que la majorité ce matin (Pacifique Time oblige car j'étudie en ce moment sur San Francisco) j'avais fini par trouver une solution hier soir. Elle fonctionne très bien mais je ne suis pas sûr qu'elle soit réellement bien optimisée/propre. Là  voici :

    &nbsp; &nbsp; <br />&nbsp; &nbsp; // Je découpe ma NSString d&#039;entrée (statementQuestion) et insère chaque mot dans un NSArray (buttonArray).&nbsp; <br />&nbsp; &nbsp; buttonArray = [appDelegate.currentQuestion.statementQuestion componentsSeparatedByString:@&quot; &quot;];<br />&nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; NSMutableArray *buttonMutableArray = [[NSMutableArray alloc] init];<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; // Les variables x et y me permettent de définir la position courante du texte.<br />&nbsp; &nbsp; int x = 0;<br />&nbsp; &nbsp; int y = 0;<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; for (NSString *labelButton in buttonArray) {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; // Ce CGSize me permet de récupérer la taille exacte du texte afin d&#039;adapter au mieux la taille du future bouton.<br />&nbsp; &nbsp; &nbsp; &nbsp; CGSize theTextSize = [[NSString stringWithFormat:@&quot;%@&quot;,labelButton] sizeWithFont: [UIFont boldSystemFontOfSize: 18]];<br />&nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; int z = x + theTextSize.width;<br />&nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; // Si la position de mon nouveau mot dépasse du cadre de ma UIView je réalise un retour à  la ligne.<br />&nbsp; &nbsp; &nbsp; &nbsp; if (z &gt; questionView.frame.size.width) {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; x = 0;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; y += 35;<br />&nbsp; &nbsp; &nbsp; &nbsp; }<br />&nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; CGRect frame = CGRectMake(x, y, theTextSize.width, theTextSize.height);<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; UIButton *button = [[UIButton alloc] initWithFrame:frame];<br />&nbsp; &nbsp; &nbsp; &nbsp; [button addTarget:self action:@selector(selectAnswerAction:) forControlEvents:UIControlEventTouchUpInside];<br />&nbsp; &nbsp; &nbsp; &nbsp; [button setTitle:[NSString stringWithFormat:@&quot;%@&quot;,labelButton] forState:UIControlStateNormal];<br />&nbsp; &nbsp; &nbsp; &nbsp; [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];<br />&nbsp; &nbsp; &nbsp; &nbsp; [button setTitleColor:[UIColor colorWithRed:0.294 green:0.537 blue:0.816 alpha:1.0] forState:UIControlStateSelected];<br />&nbsp; &nbsp; &nbsp; &nbsp; button.titleLabel.font = [UIFont boldSystemFontOfSize:18];<br /><br />&nbsp; &nbsp; &nbsp; &nbsp; [buttonMutableArray addObject:button];<br />&nbsp; &nbsp; &nbsp; &nbsp; [questionView addSubview:button];&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // J&#039;ajoute mon bouton à  ma UIView.<br />&nbsp; &nbsp; &nbsp; &nbsp; [button release];<br />&nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; x += theTextSize.width + 5;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // J&#039;incrémente la position de mon texte courant. <br />&nbsp; &nbsp; <br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; buttonArray = [buttonMutableArray copy];<br />&nbsp; &nbsp; [buttonMutableArray release];<br />
    


    Qu'en pensez-vous ?

    Merci encore.
  • AliGatorAliGator Membre, Modérateur
    04:21 modifié #10
    Ton code me parait bien après une lecture en diagonale.
    (A part que ça me fait marrer de voir des trucs comme [tt][NSString stringWithFormat:@%@",labelButton][/tt]... pourquoi s'embêter à  utiliser stringWithFormat et une chaà®ne de formattage, pourquoi ne pas directement utiliser labelButton ?! mais bon)

    Après pour savoir si le mot cliqué est le bon ou le mauvais, je sais pas comment tu fais, si dans ton [tt]@selector(selectAnswerAction:)[/tt] tu te bases sur le texte du bouton c'est peut-être "dangereux" (par exemple si tu as 2 fois le même mot dans une phrase mais que le joueur ne doit en cliquer qu'un des deux...). Du coup tu peux soit chercher le sender dans ton buttonArray et récupérer l'index pour savoir l'index du mot cliqué... soit utiliser le "tag" du bouton (qu'il faut que tu affectes quand tu construis ta boucle du coup)...
  • tazkeoxtazkeox Membre
    04:21 modifié #11
    dans 1307662996:

    (A part que ça me fait marrer de voir des trucs comme [tt][NSString stringWithFormat:@%@",labelButton][/tt]... pourquoi s'embêter à  utiliser stringWithFormat et une chaà®ne de formattage, pourquoi ne pas directement utiliser labelButton ?! mais bon)


    Effectivement c'est inutile ici ^^

    dans 1307662996:

    Après pour savoir si le mot cliqué est le bon ou le mauvais, je sais pas comment tu fais, si dans ton [tt]@selector(selectAnswerAction:)[/tt] tu te bases sur le texte du bouton c'est peut-être "dangereux" (par exemple si tu as 2 fois le même mot dans une phrase mais que le joueur ne doit en cliquer qu'un des deux...).


    Je me base bien sur le texte du bouton et je n'avais pas penser à  ce cas de figure :( Une fois l'exercice terminé je récupère tous les mots sélectionnés et vérifie leur validité grâce à  une énumération du tableau des bonnes réponses. Si un mot est sélectionné deux fois alors le compte sera tout de même faux mais il est vrai que l'utilisateur pourra obtenir une réponse juste s'il sélectionne un des deux alors que ce n'est pas le bon...

    dans 1307662996:

    Du coup tu peux soit chercher le sender dans ton buttonArray et récupérer l'index pour savoir l'index du mot cliqué... soit utiliser le "tag" du bouton (qu'il faut que tu affectes quand tu construis ta boucle du coup)...


    Je vais voir pour cette solution oui; je n'ai pas l'habitude d'utiliser ce type de méthode mais ça à  l'air plus approprié. Merci ;)
Connectez-vous ou Inscrivez-vous pour répondre.