2017-10-05 5 views
2

Récemment dans notre projet il y avait un problème avec un UIBarButtonItem qui utilisait un customView. Avant iOS 11 nous avons fait la mise en page via des éléments d'espacement flexibles. Cela ne fonctionnait plus et rien n'était affiché. Parce que je n'ai pas trouvé de réponse ici sur SO qui a vraiment résolu le problème pour moi, je l'ai examiné et j'ai trouvé une solution (que je reconnais comme un hacky) que je voulais partager avec vous.Mise en page automatique Barre d'outils iOS 11 UIBarButtonItem avec customView

Peut-être que cela peut vous aider ou avoir des commentaires. C'est un code mixte d'objc et de swift, j'espère que cela ne vous dérange pas.

Répondre

7

Comme le montre la WWDC vidéo Updating Your App for iOS 11:

«Et maintenant dans iOS 11, barre d'outils de l'interface utilisateur et la barre de navigation de l'interface utilisateur ont tous deux support complexe et express pour la mise en page automatique »

Ma première étape a consisté à utiliser des contraintes de mise en page sur lui-même, il vue personnalisée:

UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithCustomView:customView]; 
    [barButtonItem.customView.widthAnchor constraintEqualToConstant:375].active = YES; 
    [barButtonItem.customView.heightAnchor constraintEqualToConstant:44].active = YES; 

Cela a donné lieu à la barre d'outils montrant le CustomView. Le problème était que gauche et droite de la vue, il y avait un écart. Et vous pourriez le voir. J'ai donc regardé dans l'outil Visualiser le débogage de la hiérarchie et réalisé, il y a un UIToolbarContentView sur la barre d'outils. Ce contenu a la bonne taille (en particulier la largeur) et j'ai commencé à me demander. J'ai regardé la seule sous-vue que contentView avait et c'était un UIBarButtonStackView. Cette stackView limitait en quelque sorte mon customView en termes de largeur.

il ressemble à ceci:

contentView |<-fullWidth-------->| 
stackView  |<-reducedWidth->| 
customView |<-reducedWidth->| 

Ce qui m'a fait curios était, que le CustomView n'est pas une sous-vue de la stackView. C'est probablement une conséquence de l'inclusion de customView dans UIBarButtonItem. Toutes les contraintes (supplémentaires) sur customView sont restées sans modification (ou se sont bloquées car les vues ne sont pas dans la même hiérarchie).

Après learing tout cela, j'ai ajouté une extension du UIToolbar:

extension UIToolbar { 
    private var contentView: UIView? { 
     return subviews.find { (view) -> Bool in 
      let viewDescription = String(describing: type(of: view)) 
      return viewDescription.contains("ContentView") 
     } 
    } 

    private var stackView: UIView? { 
     return contentView?.subviews.find { (view) -> Bool in 
      let viewDescription = String(describing: type(of: view)) 
      return viewDescription.contains("ButtonBarStackView") 
     } 
    } 

    func fitContentViewToToolbar() { 
     guard let stackView = stackView, let contentView = contentView else { return } 
     stackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true 
     stackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true 
     stackView.widthAnchor.constraint(equalTo: contentView.widthAnchor).isActive = true 

    } 
} 

donc ce qu'il fait est le suivant: Il obtient le contentView des sous-vues en comparant les noms de « contentView » et obtient la stackView en faisant la même chose sur contentView. Probablement un return subviews.first ferait la même chose, mais je voulais être sûr. Ensuite, les contraintes de disposition sont définies et voila: cela fonctionne dans toute la largeur.

J'espère que quelqu'un trouvera cela utile. S'il y a des commentaires: je suis très ouvert aux commentaires sur celui-ci. Peut-être que j'ai raté quelque chose et tout cela n'est même pas nécessaire. Edit: La fonction 'find' est une extension de Sequence. Il ne « filter.first » et ressemble à ceci:

extension Sequence { 
    func find(_ isIncluded: (Self.Element) throws -> Bool) rethrows -> Self.Element? { 
     return try filter(isIncluded).first 
} 

}

+0

L'écart peut être défini par les quelque layoutMargins par défaut, sont normalement Wich 8 points de chaque côté. Pour quelque raison ici, ils sont 16 points 'H: | - (16) - [_UIButtonBarStackView'. – grethi

+0

La solution ci-dessus est en conflit avec certaines contraintes déjà définies pour le stackView ... '" "'! – grethi

+0

Merci pour le heads-up. Je n'ai pas remarqué. Peut-être qu'il est possible de les supprimer à l'avance. Même si cela ressemble de plus en plus à du bidouillage dans les internes d'UIKit ... – lucasl