(Réglé) Adapter la taille d'une UIScrollView à  son contenu

Ben77650Ben77650 Membre
juillet 2014 modifié dans API UIKit #1

Bonjour à  tous


 


J'aimerais adapter la taille de ma UIScroll à  son contenu.


 


J'ai tout de suite pensé à  la propriété sizeToFit mais ça ne marche visiblement pas.


 


J'ai également testé ce code trouvé sur le net mais sans succès (la taille est fixe)



-(void)setContentSizeOfScrollView:(UIScrollView*)scroll
{
CGRect rect = CGRectZero;

for(UIView * vv in [scroll subviews])
{
rect = CGRectUnion(rect, vv.frame);
}

[scroll setContentSize:CGSizeMake(rect.size.width, rect.size.height)];
}

Ps: Le sujet à  été supprimé, je ne sais pourquoi


Mots clés:

Réponses

  • YannYann Membre
    avril 2014 modifié #2

    Salut,

     

    Perso je fais un truc dans ce genre la :

     



    // Initialisation de la scrollView
    float maxHeight = 0.0f;

    for (UIView *child in _scrollView.subviews) {
    float childHeight = child.frame.origin.y + child.frame.size.height;
    if (childHeight > maxHeight) {
    maxHeight = childHeight;
    }
    }

    [_scrollView setScrollEnabled:YES];
    [_scrollView setContentSize:CGSizeMake(320, maxHeight)];
    self.automaticallyAdjustsScrollViewInsets = NO;

    ça marchouille, mais ce n'est surement pas la meilleure façon de faire ...


  • AliGatorAliGator Membre, Modérateur
    Adapter la taille de ta scrollView, c'est à  dire, adapter sa frame (taille externe / visible) ou sa contentSize (taille du contenu scrollable, sans modifier la taille de la scrollView elle-même) ?

    Car ton code s'occupe du 2e cas (de toute façon je vois pas l'intérêt d'avoir une scrollview dans le premier cas, si la vue affiche tout son contenu et que y'a plus à  scroller...).

    Sinon ça veut dire quoi "ça ne marche pas" ? Ca fait quoi au juste, ça adapte la contentSize mais cette dernière n'est pas bonne ? Tu peux scroller mais tu as des parties de ton contenu qui ne peuvent jamais être atteintes car tu ne peux pas scroller assez loin ? Tu ne peux pas scroller du tout ? Ca ne change rien avant/après ? C'est vague un "ça marche pas", faut être plus précis quand tu décris un problème !


    Sinon de ce que je vois de ton code, il y a un cas qui n'est pas forcément bien géré, c'est si aucune des subviews n'est en (0,0). Tu fixes la contentSize à  la taille de ton rectangle englobant toutes les subviews, mais si ce rectangle englobant est par exemple (100,100,500,500), tu devrais indiquer à  ta scrollView que son contenu peut scroller jusqu'à  600x600 et non pas jusqu'à  500x500 !

    Donc en dernière ligne, je mettrais plutôt :
    [scroll setContentSize:CGSizeMake(CGRectGetMaxX(rect), CGRectGetMaxY(rect)];
  • Ben77650Ben77650 Membre
    avril 2014 modifié #4

    Ce que je cherche c'es adapter sa ContentSize


     


    Bah en fait quand je met uniquement



    self.scroll.delegate=self;
        [self.scroll setScrollEnabled:YES];
        [self.scroll sizeToFit];

    Cela ne scrolle pas


  • Ben77650Ben77650 Membre
    avril 2014 modifié #5

    -(void)setContentSizeOfScrollView:(UIScrollView*)scroll
    {
        CGRect rect = CGRectZero;
        
        for(UIView * vv in [scroll subviews])
        {
            rect = CGRectUnion(rect, vv.frame);
        }
        
        [scroll setContentSize:CGSizeMake(CGRectGetMaxX(rect), CGRectGetMaxY(rect))];
    }

    Certains éléments de ma vue ne sont pas affichés avec cette méthode (ceux se trouvant au bas de la vue).


     


     


    Si je fais 



    -(void)setContentSizeOfScrollView:(UIScrollView*)scroll
    {
        CGRect rect = CGRectZero;
        
        for(UIView * vv in [self.view subviews])
        {
            rect = CGRectUnion(rect, vv.frame);
        }
        
        [scroll setContentSize:CGSizeMake(320, CGRectGetMaxY(rect))];
    }

    Ma UIScrollView fait encore une fois une hauteur fixe de 568.0. Et j'ai préféré fixer une largeur pour que ça ne soit pas scrollable horizontalement


     


    Ps: Désolé je ne peut visiblement pas éditer le post précédent


  • Bonjour,


     


    Je n'ai toujours pas trouvé la solution par moi même et donc je reste preneur de vos différentes idées.


     


    Merci d'avance


  • CéroceCéroce Membre, Modérateur


    Ma UIScrollView fait encore une fois une hauteur fixe de 568.0. 


     




    Normal, puisque ce n'est pas la frame de la scrollview que tu as changé, mais sa contentSize.

  • Ben77650Ben77650 Membre
    avril 2014 modifié #8

    Je me suis mal exprimé je veut dire, que la contentSize est toujours de 568.0


     


    Enfin c'est quand je fais:



    NSLog(@CGRectGetMaxY(rect) %f,CGRectGetMaxY(rect));
  • Je viens de tester la solution proposée par Yann, et toujours le même problème, il m'affiche pas l'entièreté de la scrollView, toute une partie n'est pas affichée


  • Hello je bloque toujours sur ce souci.


     


    Avez-vous des idées svp ?


  • Alf1996Alf1996 Membre
    mai 2014 modifié #11

    Si tu avais posté dans la bonne section tu aurais peut être plus de chances, car il semblerait que ton code soit de l'iOS...


     


    Modérateur: déplacé dans la section adéquate.


  • CéroceCéroce Membre, Modérateur


     


    Avez-vous des idées svp ?




    Non, parce que nous ne comprenons pas ce qui te pose problème, sachant que nous t'avons déjà  expliqué comment faire.


    Peut-être qu'avec une copie d'écran, nous comprendrions mieux.

  • Tout à  fait.


     


    A l'heure actuelle, sur certaines annonces (les plus longues), j'ai le droit à  cela:


    http://image.noelshack.com/fichiers/2014/19/1399295087-capture-d-ecran-2014-05-05-a-15-03-58.png


     


    A savoir qu'il ne m'affiche pas le texte en entier, ni les boutons en dessous.


     


    Quand l'annonce est plus courte en revanche plus aucun souci:


    http://image.noelshack.com/fichiers/2014/19/1399295087-capture-d-ecran-2014-05-05-a-15-04-38.png


  • CéroceCéroce Membre, Modérateur
    mai 2014 modifié #14

    Ce n'est pas clair pour moi: les boutons verts doivent-ils être affichés en permanence ou non ? Si oui, alors ils ne doivent pas être mis dans la scroll view.


  • Ben77650Ben77650 Membre
    mai 2014 modifié #15

    Oui ils doivent être affichés en permanence, mais en dessous la description de l'article vendue, d'où le fait qu'ils soient dans la UIScrollView (c'est dans la cahier des charges que j'ai reçu, je ne peut pas faire autrement)


  • CéroceCéroce Membre, Modérateur

    Bon, donc en fait il ne sont pas affichés en permanence, puisqu'il faut faire défiler la scrollview.


    Je pense donc que l'exemple donné dans la première image ne va pas parce qu'on ne peut pas défiler assez pour voir ces boutons.


     


    Dans ce cas, ça se règle bien en travaillant sur le contentSize de la scrollview. La question est pourquoi le rectangle englobant de toutes les subviews est faux.


  • AliGatorAliGator Membre, Modérateur

    Je comprend pas trop le problème, je ne vois aucun souci avec les captures sus-postées.


     


    Si ton annonce est trop longue, forcément tes boutons étant à  la fin de ton long texte d'annonce ne vont pas être visible tant que tu ne scrolles pas. Et évidemment, si tu scrolles pour faire défiler ton annonce, tu vas retrouver tes boutons à  la fin, non? Ou alors c'est justement ça qui ne marche pas, tu aimerais pouvoir scroller mais le scroll ne fonctionne pas ?


  • @Céroce: Oui on ne vois ni ces boutons, ni la suite (ou la fin) de la description de l'article vendu.


    Comment ça le rectangle est faux ?


     


    J'ai fait ça pour info:



    self.scroll.delegate=self;
        [self.scroll setScrollEnabled:YES];
        [self setContentSizeOfScrollView:self.scroll];


    -(void)setContentSizeOfScrollView:(UIScrollView*)scroll
    {
        CGRect rect = CGRectZero;
        
        for(UIView * vv in [self.view subviews])
        {
            rect = CGRectUnion(rect, vv.frame);
        }
        NSLog(@CGRectGetMaxY(rect) %f,CGRectGetMaxY(rect));
        //renvoie tout le temps 568.00

        [scroll setContentSize:CGSizeMake(320, CGRectGetMaxY(rect))];
    }

    @AliGator: Le souci c'est que la 1ère capture que tu vois, représente le bas de l'UIScrollView, donc il manque clairement du contenu. Tel que dans la capture n°1, même en "forçant" le scroll (en tirant pour voir le bas), je ne vois même pas les boutons


  • AliGatorAliGator Membre, Modérateur
    C'est normal ton code boucle pour calculer la taille sur les subviews de ta self.view et donc retourne la taille englobante uniquement des vues qui sont au premier niveau de ta vue, au lieu de boucler sur les subviews de ta scrollView et calculer la taille de ce qu'il y a à  l'intérieur de ta scrollView.
  • Remplacer self.view par self.scroll ne change absolument rien au souci.


     


    La taille a même été réduite à  426.00



    -(void)setContentSizeOfScrollView:(UIScrollView*)scroll
    {
        CGRect rect = CGRectZero;
        
        for(UIView * vv in [self.scroll subviews])
        {
            rect = CGRectUnion(rect, vv.frame);
        }
        NSLog(@CGRectGetMaxY(rect) %f,CGRectGetMaxY(rect));
    //renvoie 426.00
        
        [scroll setContentSize:CGSizeMake(320, CGRectGetMaxY(rect))];
    }
  • AliGatorAliGator Membre, Modérateur
    mai 2014 modifié #21
    Bah debug un peu !! Met des logs dans ta boucle for pour voir sur quelles subviews il boucle et la frame de chacune, si tu veux comprendre un peu ce qui ce passe, etc.
  • Bon j'ai fait ça:



    for(UIView * vv in [scroll subviews])
    {
    rect = CGRectUnion(rect, vv.frame);
    NSLog(@scroll subviews: %@", [scroll subviews]);
    }

    Cela me renvoie ça et 17 fois


     



    2014-05-06 10:01:15.767 MyApp[1404:60b] scroll subviews: (


        "<UILabel: 0x109236e80; frame = (70 20; 148 21); text = 'Ville'; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x10922ba70>>",


        "<UILabel: 0x109222cf0; frame = (10 50; 290 21); text = 'Cat\U00e9gorie'; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x109231020>>",


        "<UILabel: 0x109223f70; frame = (219 20; 81 21); text = 'Date'; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x1092240b0>>",


        "<UILabel: 0x10922c240; frame = (10 73; 290 52); text = 'Objet'; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x10922c380>>",


        "<UILabel: 0x10923b730; frame = (10 120; 267 21); text = 'Vendu par'; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x10923b870>>",


        "<UILabel: 0x10923b260; frame = (10 149; 91 21); text = 'Prix'; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x10923b3a0>>",


        "<UILabel: 0x109223c20; frame = (10 20; 50 21); text = 'CP'; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x109223d60>>",


        "<UILabel: 0x1092337f0; frame = (10 405; 290 21); text = 'Description'; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x109233930>>",


        "<UIView: 0x10923a8a0; frame = (10 238; 301 161); autoresize = RM+BM; layer = <CALayer: 0x10923a960>>",


        "<UIImageView: 0x10922ae70; frame = (10 178; 50 50); autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x10922d360>>",


        "<UIImageView: 0x10922b010; frame = (70 178; 50 50); autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x10922b110>>",


        "<UIImageView: 0x109227980; frame = (130 178; 50 50); autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x109227a80>>",


        "<UIImageView: 0x109227bc0; frame = (190 178; 50 50); autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x109227cc0>>",


        "<UIImageView: 0x10922c000; frame = (250 178; 50 50); autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x10922c100>>",


        "<UIImageView: 0x10923c0f0; frame = (285 123; 15 15); autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x10923c1f0>>",


        "<UIImageView: 0x10923c4a0; frame = (313 395.5; 7 3.5); alpha = 0; opaque = NO; autoresize = TM; userInteractionEnabled = NO; layer = <CALayer: 0x10922f780>>",


        "<UIImageView: 0x10923c8b0; frame = (316.5 392; 3.5 7); alpha = 0; opaque = NO; autoresize = LM; userInteractionEnabled = NO; layer = <CALayer: 0x10923c6f0>>"


    )


     


  • AliGatorAliGator Membre, Modérateur

    Ce qui explique donc le résultat que tu as.


     


    (Ne connaissant pas ta hiérarchie de vues dans ta scrollview, on ne peut pas débuguer pour toi et savoir si ces subviews sont celles attendues ou pas, etc. Par exemple je ne vois pas de UIButton dans la liste des subviews qui sont parcourues, mais elles sont peut-être elles-même en subviews d'une UIView, mais ça sans boule de cristal et sans ton projet, nous on peut pas deviner)


  • Les "boutons" sont en réalité des images sur lesquels je fais ça



    UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action: @selector(onImageViewClicked)];
    singleTap.numberOfTapsRequired = 1;
    singleTap.numberOfTouchesRequired = 1;
    [self.image1 addGestureRecognizer:singleTap];
  • Ben77650Ben77650 Membre
    mai 2014 modifié #25

    Bon finalement j'ai trouvé mon erreur


     


    Je mettais ce code au début du viewDidLoad alors que je créais du contenu dedans, forcément une fois mis à  la fin de la fonction ça marche beaucoup mieux.


  • AliGatorAliGator Membre, Modérateur
    T'as pas l'impression de tourner en boucle ? On te suggère de debuguer, de vérifier en particulier que tu boucles bien sur toutes les subviews que tu as dans ton XIB et que les frames de ces subviews correspondent bien chacune à  ce que tu attends comme position pour ces vues, etc... et à  la fin ça revient toujours à  ton message "ça marche pas" sans qu'on ait l'impression que tu aies fait grand chose de plus...


    C'est à  toi de creuser car toi seul connaà®t ta hiérarchie de vue et les positions (frames) attendues de ces vues donc toi seul saura dire si ce log correspond à  ce que tu as dans ton XIB vu que nous on ne l'a pas sous les yeux (et on ne sait pas ce que tu fais à  coté, si tu changes les frames par code, les autoresizingMasks ou contraintes positionnées... on peut pas deviner sans être devant ton projet)


    Quand je vois les frames affichées dans ton log le résultat que tu obtiens me semble tout à  fait logique. Donc soit tu as des vues qui ne sont pas encore en subviews au moment où tu appelles ce code et donc elles ne sont pas prises en compte car n'existent pas à  ce moment là , soit tu appelles ton code alors que tes vues ne sont pas encore à  leur frame/position finale... à  toi de creuser, mettre des break points et des logs et surtout comparer ces frames avec ce que tu attends.
  • Bon visiblement tu as répondu à  mon message avant édition ^^


     


    Je disais donc après édition que j'ai finalement trouvé la solution et donc réglé le souci


  • CéroceCéroce Membre, Modérateur


     


    Les "boutons" sont en réalité des images sur lesquels je fais ça




    Non seulement c'est compliqué, mais tu perds une fonctionnalité: quand on appuie sur l'image, elle ne change pas d'état. Le feedback est quelque chose de très important.

  • Comment ça elle ne change pas d'état ?


     


    Je comptais faire un booléen, pour l'image de favori, afin de savoir si elle est en favori (1) ou non (0)


  • Sinon y a le UIBouton qui fait ça aussi, il fait l'état repos ou non et sélectionné ou non. Du coup il gère sans se fatiguer le fait que la personne est en train de cliquer dessus ou non et le fait de savoir si l'objet est en favoris ou non et ceci en écrivant deux lignes de codes que tout le monde a déjà  testé des centaines de fois. Tu es un peu en train de réinventer la roue. Après ta solution marchera, y a pas de souci.


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