[Résolu] Problème d'affichage d'une UIToolBar définie par programme

Alf1996Alf1996 Membre
mars 2016 modifié dans API UIKit #1

Bonjour à  tous,


 


çà  fait un moment que je n'ai pas posé de question technique ici, mais après pas mal de recherches, et une nuit qui ne m'a pas porté conseil je n'arrive pas à  m'en sortir...


 


J'ai créé une vue très simple de façon programmatique, avec une MkMapVue et une UIToolbar, et j'ai deux problèmes :


- au premier affichage, l'UIToolbar ne s'affiche pas ; elle ne 'affiche qu'après avoir fait pivoter l'écran au moins une fois.


- la ToolBar ne se positionne pas bien en bas, et surtout le problème est différent suivant que je suis sur iPad ou iPhone. Sur iPad, le positionnement est correct, alors que sur iPhone, il y a une bande noire sous la ToolBar en format paysage, et au contraire, la Toolbar est tronquée en format portrait.


 


Voici le code :



#define TOOLBAR_HEIGHT 44.


- (void)viewDidLoad {
[super viewDidLoad];
CGRect rect=[[UIScreen mainScreen] bounds];
_myMap = [[MKMapView alloc] initWithFrame:rect];
[self.view addSubview:_myMap];

_theToolBar = [[UIToolbar alloc] init];
UIBarButtonItem *infoButtonItem=[[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@InfoImage.png] style:UIBarButtonItemStylePlain target:self action:@selector(showInfo)];
UIBarButtonItem *helpButtonItem=[[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@HelpImage.png] style:UIBarButtonItemStylePlain target:self action:@selector(showHelp)];
UIBarButtonItem *settingButtonItem=[[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@SetupImage.png] style:UIBarButtonItemStylePlain target:self action:@selector(showOptions)];
UIBarButtonItem *flexSpace=[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];

_theToolBar.items = [NSArray arrayWithObjects:infoButtonItem,flexSpace,helpButtonItem,flexSpace,settingButtonItem,nil];
[_theToolBar setHidden:NO];
[self.view addSubview:_theToolBar];
}

- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
CGRect rect=[[UIScreen mainScreen] bounds];
[self redraw:rect];
}

-(void) redraw:(CGRect)rect {
[_myMap setFrame:rect];
CGRect toolbarRect=CGRectMake(rect.origin.x, rect.size.height-TOOLBAR_HEIGHT, rect.size.width, TOOLBAR_HEIGHT);
[_theToolBar setFrame:toolbarRect];
}

-(BOOL) shouldAutorotate {
return YES;
}

-(void) viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
[self redraw:CGRectMake(0., 0., size.width, size.height)];
}


Et une illustration du résultat sur iPhone :


en paysage :


Mots clés:

Réponses

  • CéroceCéroce Membre, Modérateur
    mars 2016 modifié #2
    Es-tu sûre que la toolbar mesure toujours 44 points ? J'ai un doute parce que je sais que ce n'est pas le cas pour les navigation bars sur iPhone en orientation paysage... alors qu'il me semble que la hauteur reste constante sur iPad.

    Sinon, il y a un truc qui me chagrine:
    CGRect rect=[[UIScreen mainScreen] bounds];
    Il faut te baser sur la taille de la vue parente (qui peut être la window). Par exemple, comme tu le sais, sur l'iPad Pro, l'écran peut maintenant être divisé pour avoir deux applications. Eh bien, ton code ne marche pas, puisque tu prends la taille de l'écran!
    ça peut éventuellement poser d'autres problèmes.


  • Sinon, il y a un truc qui me chagrine:



    CGRect rect=[[UIScreen mainScreen] bounds];

    Il faut te baser sur la taille de la vue parente (qui peut être la window). Par exemple, comme tu le sais, sur l'iPad Pro, l'écran peut maintenant être divisé pour avoir deux applications. Eh bien, ton code ne marche pas, puisque tu prends la taille de l'écran!

    ça peut éventuellement poser d'autres problèmes.

     




    Merci de le signaler. Je n'y aurais pas pensé et c'est vrai que cela peut poser probléme. 



  • Es-tu sûre que la toolbar mesure toujours 44 points ? J'ai un doute parce que je sais que ce n'est pas le cas pour les navigation bars sur iPhone en orientation paysage... alors qu'il me semble que la hauteur reste constante sur iPad.

     




     


    Je croyais avoir lu dans la doc que c'était 44 pts par défaut, mais j'ai dû mal lire, je vais rechercher çà ...





    Par exemple, comme tu le sais, sur l'iPad Pro, l'écran peut maintenant être divisé pour avoir deux applications. Eh bien, ton code ne marche pas, puisque tu prends la taille de l'écran!


    ça peut éventuellement poser d'autres problèmes.

     




     


    Ah oui, bien vu ! Je n'y avais pas pensé non plus...


     


    Sinon, ce ne serait pas plus simple que je crée des contraintes par code ? ... si c'est possible ?

  • Bon, j'ai trouvé une solution qui fonctionne...


    Je ne sais pas si c'est la plus élégante, n'hésitez pas si vous voyez mieux !


     


    J'ai créé une méthode qui définit des contraintes :




    -(void) setupConstraints {
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:_theToolBar
    attribute:NSLayoutAttributeWidth
    relatedBy:NSLayoutRelationEqual
    toItem:self.view
    attribute:NSLayoutAttributeWidth
    multiplier:1.
    constant:0]];
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:_myMap
    attribute:NSLayoutAttributeWidth
    relatedBy:NSLayoutRelationEqual
    toItem:self.view
    attribute:NSLayoutAttributeWidth
    multiplier:1.
    constant:0]];
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:_theToolBar
    attribute:NSLayoutAttributeBottom
    relatedBy:NSLayoutRelationEqual
    toItem:self.view
    attribute:NSLayoutAttributeBottom
    multiplier:1.
    constant:0]];
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:_theToolBar
    attribute:NSLayoutAttributeTop
    relatedBy:NSLayoutRelationEqual
    toItem:_myMap
    attribute:NSLayoutAttributeBottom
    multiplier:1.
    constant:0.]];
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:_myMap
    attribute:NSLayoutAttributeLeading
    relatedBy:NSLayoutRelationEqual
    toItem:self.view
    attribute:NSLayoutAttributeLeading
    multiplier:1.
    constant:0]];
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:_myMap
    attribute:NSLayoutAttributeTop
    relatedBy:NSLayoutRelationEqual
    toItem:self.view
    attribute:NSLayoutAttributeTop
    multiplier:1.
    constant:0]];

    [self.view setNeedsUpdateConstraints];
    }


    que j'appelle dans le viewDidLoad, et dans le viewWillTransitionTo Size, je mets à  jour les contraintes.



    -(void) viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
    [self.view setNeedsUpdateConstraints];
    }


    Merci Céroce pour ton intervention.  

  • CéroceCéroce Membre, Modérateur

    Comme tu le fais me parait la meilleure solution.


  • Merci Céroce.    


    Je mets le sujet en "résolu"...


  • Joanna CarterJoanna Carter Membre, Modérateur

    Bonjour Alf


     


    Bien que tu as "réussi" avec le code, je me demandais pourquoi le code ?


     


    J'ai fait la même chose en 4 minutes avec un storyboard, complètement sans code - regardes-toi ci-joint


    Alf.png 73.6K
  • Hi Joanna !


     


    Je suis même sûre que tu as mis moins de 4 minutes !!!


    En fait, c'était plus un "challenge" ! Jusque là  j'avais déjà  fait pas mal de vues par programme, mais jamais pour une application universelle, gérant la rotation. Mais je te l'accorde, c'est beaucoup plus simple avec storyboard surtout avec les size class.


     


    Merci tout de même.


  • Joanna CarterJoanna Carter Membre, Modérateur
    mars 2016 modifié #10

    OK, si tu insistes  ::)


     


    Voice le code le plus moderne pour iOS 9



    - (void)viewDidLoad
    {
    [super viewDidLoad];

    MKMapView *mapView = [[MKMapView alloc] init];

    mapView.translatesAutoresizingMaskIntoConstraints = NO;

    UIToolbar *toolbar = [[UIToolbar alloc] init];

    UIBarButtonItem *infoButtonItem = [[UIBarButtonItem alloc] initWithTitle:@Info style:UIBarButtonItemStylePlain target:nil action:nil];

    UIBarButtonItem *helpButtonItem = [[UIBarButtonItem alloc] initWithTitle:@Help style:UIBarButtonItemStylePlain target:nil action:nil];

    UIBarButtonItem *settingButtonItem = [[UIBarButtonItem alloc] initWithTitle:@Setup style:UIBarButtonItemStylePlain target:nil action:nil];

    UIBarButtonItem *flexSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];

    toolbar.items = @[;infoButtonItem, flexSpace, helpButtonItem, flexSpace, settingButtonItem];

    toolbar.translatesAutoresizingMaskIntoConstraints = NO;

    [self.view addSubview:mapView];

    [self.view addSubview:toolbar];

    [mapView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES;

    [mapView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES;

    [mapView.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES;

    [toolbar.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES;

    [toolbar.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES;

    [toolbar.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES;

    [mapView.bottomAnchor constraintEqualToAnchor:toolbar.topAnchor].active = YES;
    }

    Et rien d'autre. Toutes les rotations sont automatiquement prises en charge, même sur tous les iBidules   :D


  • Merci Joanna ! 


     


    Les contraintes sont effectivement beaucoup plus simples que ce que j'avais fait.   :D   :D   :D

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