Choix de vues pour appli iphone - UIWebView ou pas ?

LeChatNoirLeChatNoir Membre, Modérateur
18:34 modifié dans Vos applications #1
Salut,
Je suis en train de faire une application iPhone qui consiste à  naviguer dans des listes de sites et quand on arrive sur le détail, présentation de pas mal d'infos.
Pour chaque site, la structure des infos de détail serait la même mais la quantité d'info pourra différer.
Parmi ces infos, certaines seraient également des liens ou renvois vers d'autres zones d'info.

Au final, je ne sais pas trop comment faire.

J'ai vu qu'une UIWebView pouvait permettre de charger du code HTML local et serait a priori plutot souple pour ce que je veux faire. Mais la question des renvois/liens semble plus fastidieuse...

L'autre alternative est donc une UIView standard mais ca signifie du coup du code plus complexe avec dimensionnement des contrôles, positionnement, etc par code.

Je voulais juste avoir l'avis des habitués comme vous.

Qu'est ce vous en dites ?

Réponses

  • LeChatNoirLeChatNoir Membre, Modérateur
    18:34 modifié #2
    ** Bah moi aussi je mets une tête toute triste alors **
    [move] :'( [/move]
  • AliGatorAliGator Membre, Modérateur
    mars 2010 modifié #3
    En fait ça dépend à  quel point tes vues sont modulables.

    Perso j'ai déjà  fait, et uniquement avec des UIView (enfin pas avec une UIWebView quoi), des layout de vues modulables. Il suffit de créer une classe par exemple StackView (dérivant de UIView) qui va positionner automatiquement ses subviews les unes en dessous des autres (en fonction de leur tailles respectives) dans son layoutSubviews.
    Comme ça tu n'as plus qu'à  faire tous tes [tt][maStackView addSubview:vueA][/tt], [tt][maStackView addSubview:vueB][/tt], [tt][maStackView addSubview:vueC][/tt]... et les vues vont se mettre toutes seules les unes en dessous des autres sans qu'il n'y ait de trous. Et si tu removeFromSuperview ta vueB ensuite, par exemple, hop, ta StackView va automatiquement réarranger ses subviews donc remonter vueC pour occuper l'espace laissé vide au lieu de laisser un trou.

    [PS Modérateur]
    Sujet déplacé dans le forum "Vos projets d'application iPhone" qui est plus adéquat (et fait pour ce genre de question)
  • LeChatNoirLeChatNoir Membre, Modérateur
    18:34 modifié #4
    Cool, merci Ali !
    J'ai expérimenté dans mon coin un peu tout ça et le HTML, c'est sympa mais c'est gavant pour plusieurs raisons :
    1 - faut gérer le HTML à  côté et ensuite, intégrer les fichiers au projet XCode ; un peu lourd
    2 - la webview annule toute action utilisateur. Elle prend tous les "gestures" et agit en fonction. J'ai pas réussi à  catcher les évènements autrement...
    3 - la mise en forme est figée de partout donc quand on veut enrichir l'HTML avec les valeurs à  afficher, ben on peut pas redimensionner comme on veut.

    Bref, une WebView pour du local, c'est pas terrible... Autant faire comme tu dis. Même si ça fait plus de boulot au départ, c'est plus flexible par la suite.

    A + !
  • 18:34 modifié #5
    dans 1268382499:

    ** Bah moi aussi je mets une tête toute triste alors **
    [move] :'( [/move]


    [move] :P :P[/move]
  • LeChatNoirLeChatNoir Membre, Modérateur
    18:34 modifié #6
    Salut,
    En fait, je me demande quel est l'intérêt de ta méthode Ali.
    Que ce soit la UIView qui fasse ça ou la View Controller, ça change rien si ?
    Dans ton viewController, tu créer tes "sous vue" et tu les ajoutes à  la vue principale et basta.
    Non ?
  • AliGatorAliGator Membre, Modérateur
    18:34 modifié #7
    Ma StackView, telle que je l'ai faite, j'ai juste implémenté le code de layoutSubviews, méthode qui est appellée automatiquement par le RunTime.
    Donc l'intérêt de ma StackView, c'est que t'as juste à  faire [stackView addSubview:v1] sans avoir à  ajuster la frame de v1 pour la positionner au bon endroit. Ou [stackView insertSubview:v2 atIndex:3] sans avoir à  calculer la position de v2 mais aussi de toutes les autres vues qui vont être décalées à  cause de l'insertion de cette vue v2. layoutSubviews est appelé automatiquement par le runtime quand tu fais addSubview, removeFromSuperview, insertSubview:atIndex: etc... donc tu n'as aucun code à  mettre ni à  appeler dans ton ViewController avant ou après l'ajout de tes vues pour calculer leur frame pour les positionner comme il faut les unes par rapport aux autres avec des calculs savants de cumul de hauteur et tout.

    Si tu mettais le code (qui recalcule la position de toutes les vues les unes par rapport aux autres) dans le ViewController, ça marche aussi... sauf qu'il faut appeler la méthode à  chaque fois que tu modifies la vue pour ajouter des subviews ou en enlever, ou même à  chaque fois également que ta vue principale change de taille (par exemple lors d'une rotation du device), ...
  • LeChatNoirLeChatNoir Membre, Modérateur
    18:34 modifié #8
    ah ok.
    Donc tu créer tes subviews dans ton controller en définissant le contenu, la taille mais pas l'origin.
    Et c'est ta StackView qui se débrouille de la positionner dans la méthode layoutSubview

    Pas bête l'aligator :-)
  • AliGatorAliGator Membre, Modérateur
    18:34 modifié #9
    Exactement ;)

    Ou même tu crées tes subviews en vrac dans IB, avec la bonne taille mais en te foutant de leur position, ça marche aussi.
    Bon, pour avoir une idée du rendu directement dans IB, autant les placer à  peu près bien dès le départ, mais d'une part tu n'est pas obligé de les placer au pixel près puisque le layoutSubviews va de toute façon bien les replacer tout seul, et surtout d'autre part si -- ce qui semble être ta préoccupation principale -- tu ajoutes ou supprimes (ou masque) des subviews à  la volée selon les cas des données à  afficher (dans un cas afficher vue1, vueB et vueD, dans l'autre cas vueA et vueC, dans l'autre cas vueB, vueC, vueE, ...), elle se remettrons toutes seules en place sans que tu aies à  recalculer leur frame à  la main pour chaque cas différent.
  • LeChatNoirLeChatNoir Membre, Modérateur
    18:34 modifié #10
    Ah ouais, pas con l'idée de les chopper dans IB...
    Ca évite tout le code pour la police, la couleur, etc...
    Du coup tu mets ça dans une vue cachée et tu te sers au besoin pour les afficher dans ta vue principale (enfin celle qui est visible) ?
  • AliGatorAliGator Membre, Modérateur
    mai 2010 modifié #11
    Deux solutions pour gérer l'ensemble de tes vues Vx que tu compte mettre en subview de ta vue principale (que l'on va appeler StackView)

    1) Mettre toutes ces vues en subview de ta StackView dans IB, et par code juste les rendre visible ou hidden par le code. Bon dans mon code de layoutSubviews de ma StackView à  moi, je n'ai pas gérer le cas des vues hidden, je sais pas si c'est une idée valable, mais bon)

    2) Ne pas les mettre en subview de ta StackView dans IB, et les rajouter et supprimer en tant que subview de ta StackView à  la volée par le code. Option vers laquelle je partirais pour ma part.
    Et dans ce cas, aucun besoin de les mettre dans une vue cachée. Il suffit d'avoir un IBOutlet vers ces vues dans ton XIB.

    Ainsi dans ton XIB tu auras ton File's Owner (correspondant à  ton ViewController donc), ta View (liée à  la propriété .view du File's Owner / ViewController) contenant ta StackView (à  moins que ta StackView soit directement la vue racine de ton ViewController), et toutes tes autres vues V1, V2, ... Vn que tu vas ajouter ou non à  la volée à  ta StackView. Tu prévois dans ton ViewController un IBOutlet pour chaque vue Vx, et il faut juste penser à  déclarer une [tt]@property(nonatomic,retain) IBOutlet UIView* Vx[/tt] pour chaque vue, histoire que lesdites vues soient "retain", et que tu puisses les manipuler sans qu'elles disparaissent de la mémoire même si elles ne sont pas dans la view hierarchy (même si elles ne sont pas subviews d'une vue parente parce que justement à  un instant T tu ne les mets pas toutes dans ta StackView, selon la configuration que tu veux afficher, et donc il faut que celles qui ne soient pas dans ta StackView ni dans aucune autre superview soient qd mm retenues pour ne pas être déallouées automatiquement)

    Enfin c'est pas compliqué dans les faits (c'est pas parce que j'écris un gros pavé qu'il faut que ça te fasse peur), cf juste ce paragraphe dans les Programming Guides de la doc Apple qui explique la "object retention in XIB files" (cas différent sous OSX et iPhoneOS)
  • LeChatNoirLeChatNoir Membre, Modérateur
    18:34 modifié #12
    ouais ok.
    J'ai tout compris.
    Je vais opter pour la solution 2 qui me parait très bien.
    Merci à  qui ?
    Merci Ali  :P
  • LeChatNoirLeChatNoir Membre, Modérateur
    18:34 modifié #13
    Salut,
    J'ai commencé à  expérimenter et la méthode layoutSubviews ne me semble pas indiqué.
    En effet, ma vue container est une scrollView.
    Et layoutSubviews est appelée plein de fois quand on scroll !
    Du coup, ça risque de pas être très performant...

    Je reste donc sur la solution 2 mais je vais plutot surcharger addSubView et remove...

    A+
  • AliGatorAliGator Membre, Modérateur
    18:34 modifié #14
    Sauf si tu fais en sorte que ta vue container ne soit pas ta scrollview, mais une UIView classique... qui serait la seule et unique subview de ta scrollview.
  • LeChatNoirLeChatNoir Membre, Modérateur
    18:34 modifié #15
    Exact !
    Ca fonctionne...

    Par contre, du coup, dans le layoutSubviews, tu parcours systématiquement la viewHierarchy avec positionnement à  chaque fois ?

    Genre :
    for (NSView * currentView in [self subviews]) {
      if ([currentView isKindOfClass:[UILabel Class]]) alors....
      tatati, tatata
    }

    Un truc du style ?
  • AliGatorAliGator Membre, Modérateur
    18:34 modifié #16
    Heu oui, sauf que pourquoi le test isKindOfClass ?
    Genre si je veux que mes vues s'entassent les unes sous les autres :
    float y = 0;<br />for(UIView* v in self.subviews) {<br />&nbsp; v.frame = CGRectMake(v.frame.origin.x , y, v.frame.size.width, v.frame.size.height);<br />&nbsp; y += v.frame.size.height;<br />}
    
    J'ai un peu plus que ça car je gère les margins, et j'ai un mode d'empilement vertical et un horizontal (le test est fait hors de la boucle for pour éviter la répétition des "if" à  chaque itération).

    Et si je veux des layouts plus complexes, plutôt que de faire des calculs alambiqués, j'imbrique les StackViews : Une HStackView contenant des VStackViews contenant des HStackViews, etc...

    En fait j'ai rien inventé, j'ai repris ce modèle sur tous les frameworks qui ont des objets dédiés au layout, genre Qt ou Android. Il me manque plus que les éléments FixedSpace et FlexibleSpace que je pourrais gérer en plus pour faire des trucs totalement flexibles (un peu comme ceux qu'on utilise dans les UIToolBar) mais bon... je suis pas allé si loin
  • LeChatNoirLeChatNoir Membre, Modérateur
    18:34 modifié #17
    ok merci Ali.
    Les isKindOfClass, c'est pour gérer des alignements différents.
    Genre mes UILabel, je les mets à  gauche, j'ai des UIImage que je veux mettre plus au centre, etc...
    En tous cas, merci pour toutes ces infos !
    A+
  • LeChatNoirLeChatNoir Membre, Modérateur
    18:34 modifié #18
    dans 1273659000:

    J'ai un peu plus que ça car je gère les margins, et j'ai un mode d'empilement vertical et un horizontal (le test est fait hors de la boucle for pour éviter la répétition des "if" à  chaque itération).


    Tiens à  ce sujet, je suis en train de regarder le pb de l'orientation.
    Pour placer mes vues, j'utilise [[UIScreen mainScreen] applicationFrame].size histoire de pas avoir les valeurs en dur (l'iphone HD risque d'avoir des vues de plus 320).

    Or, quelle que soit l'orientation, width reste le meme côté.
    Donc faudrait que je teste l'orientation pour pouvoir savoir si la largeur est width ou height...

    2eme pb, dans le simulateur, lors du lancement, l'orientation est tjs "Unknown"... (j'utilise [[UIDevice currentDevice] orientation])

    Bref, je peux traiter tous ces points mais ca me parait un peu lourd...
    Je pars sur une fausse piste ?
    A+
  • AliGatorAliGator Membre, Modérateur
    18:34 modifié #19
    Ah, bon point... heu regarde du côté de la CGAffineTransform car je crois que quand il y a une rotation, en fait l'iPhone ne redimentionne pas la vue de WxH vers HxW, mais applique une CGAffineTransformMakeRotation de 90° sur la vue... ce qui visuellement a le même impact, sauf que les valeurs de width et height ne sont pas affectées du coup.
  • LeChatNoirLeChatNoir Membre, Modérateur
    mai 2010 modifié #20
    Ok.
    En fait, je viens de lire ca : http://developer.apple.com/iphone/library/featuredarticles/ViewControllerPGforiPhoneOS/ViewControllerPGforiPhoneOS.pdf

    Pour gérer les orientations avec réarrangement des infos présentées, ils conseillent de créer 2 viewController. 1 pour le portrait, 1 pour le paysage (page 42).
    Avec un viewController "père" qui "écoute" les notifications de changement d'orientation et charge le viewController approprié en conséquence.

    Ce me parait pas mal...

    En synthèse, je retiens :
    • le layoutSubviews pour empiler les sous vues (et éventuellement faire qques arrangements/alignements simples),
    • les stackview imbriquées en cas d'alignement/arrangement plus complexes,
    • les labels et autres objets graphiques dans IB avec des outlets pour les utilisés,
    • 2 controllers pour portrait/paysage


    Eh ben, ca en fait du monde pour afficher qques infos !
    Me demande si une UIWebView était pas plus simple finalement  :o

    En tous cas, je suis bien content. Mes connaissances s'enrichissent grâce à  toi Ali et j'ai l'impression de faire du bon boulot du coup !
    o:)

Connectez-vous ou Inscrivez-vous pour répondre.