web-dev-qa-db-fra.com

UINavigationItem centrant le titre

J'ai une barre de navigation avec les deux boutons de barre gauche et droite de chaque côté. J'ai une customTitlelabel que j'ai définie comme titleView de la UINavigationItem

[self.navigationItem setTitleView: customTitleLabel];

Tout va bien maintenant. Le problème, la taille du rightbarButton est dynamique en fonction de l'entrée que je reçois dans l'un des champs de texte. 

Par conséquent, le titre est automatiquement centré en fonction de l'espace disponible entre les boutons. 

comment puis-je définir le titre à une position fixe? 

20
Neelesh

Vous ne pouvez pas faire ce que vous voulez directement - la position de votre vue du titre est hors de votre contrôle (lorsqu'elle est gérée par UINavigationBar). 

Cependant, il existe au moins deux stratégies pour obtenir l'effet souhaité:

1) Ajoutez la vue du titre non pas en tant que vue du titre 'approprié' de la barre de navigation, mais en tant que sous-vue de la UINavigationBar. (Remarque: ceci n'est pas "officiellement" sanctionné, mais je l'ai déjà vu et fonctionne. Évidemment, vous devez surveiller votre étiquette de titre en écrasant des morceaux de boutons, et gérer des barres de navigation de différentes tailles pour différentes orientations, etc. - un peu délicat.)

2) Créez une sous-classe intelligente UIView qui affiche une sous-vue donnée (qui serait votre UILabel) à une position calculée pour afficher efficacement la sous-vue parfaitement centrée sur l'écran. Pour ce faire, votre sous-classe intelligente UIView répondrait aux événements de présentation (ou aux modifications de la propriété frame, etc.) en modifiant la position (frame) de la sous-vue de l'étiquette.

Personnellement, j'aime bien l'idée d'approche 2) la meilleure.

15
occulus

La définition de la propriété titleView de la barre de navigation fonctionne parfaitement - il n'est pas nécessaire de sous-classer ou de modifier des cadres autres que ceux de votre vue personnalisée.

L'astuce pour le centrer par rapport à la largeur totale de UINavigationBar consiste à:

  1. définir la largeur de votre vue en fonction de la taille du texte
  2. régler l'alignement sur centré et
  3. définir le masque autoresizing pour qu'il soit redimensionné par rapport à l'espace disponible

Voici un exemple de code qui crée un titleView personnalisé avec une étiquette qui reste centrée dans UINavigationBar indépendamment de l’orientation, de la largeur du bouton à gauche ou à droite:

self.title = @"My Centered Nav Title";

// Init views with rects with height and y pos
CGFloat titleHeight = self.navigationController.navigationBar.frame.size.height;
UIView *titleView = [[UIView alloc] initWithFrame:CGRectZero];
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];

// Set font for sizing width
titleLabel.font = [UIFont boldSystemFontOfSize:20.f];

// Set the width of the views according to the text size
CGFloat desiredWidth = [self.title sizeWithFont:titleLabel.font
                            constrainedToSize:CGSizeMake([[UIScreen mainScreen] applicationFrame].size.width, titleLabel.frame.size.height)
                                lineBreakMode:UILineBreakModeCharacterWrap].width;

CGRect frame;

frame = titleLabel.frame;
frame.size.height = titleHeight;
frame.size.width = desiredWidth;
titleLabel.frame = frame;

frame = titleView.frame;
frame.size.height = titleHeight;
frame.size.width = desiredWidth;
titleView.frame = frame;

// Ensure text is on one line, centered and truncates if the bounds are restricted
titleLabel.numberOfLines = 1;
titleLabel.lineBreakMode = UILineBreakModeTailTruncation;
titleLabel.textAlignment = NSTextAlignmentCenter;

// Use autoresizing to restrict the bounds to the area that the titleview allows
titleView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
titleView.autoresizesSubviews = YES;
titleLabel.autoresizingMask = titleView.autoresizingMask;

// Set the text
titleLabel.text = self.title;

// Add as the nav bar's titleview
[titleView addSubview:titleLabel];
self.navigationItem.titleView = titleView;
28
followben
override func viewDidLoad() {
    super.viewDidLoad()
    navigationController?.navigationBar.topItem?.title = ""
}

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    navigationItem.title = "Make peace soon"
}
12
neoneye

La bonne réponse consiste à remplacer le sizeThatFits: de votre titleView personnalisée et à lui renvoyer la taille du contenu. La barre de navigation centre la vue des titres personnalisés jusqu'à ce qu'il ne reste plus d'espace pour le faire.

Par exemple, si vous avez un conteneur UIView avec UILabel à l'intérieur:

@interface CustomTitleView : UIView

@property UILabel* textLabel;

@end

@implementation CustomTitleView

- (CGSize)sizeThatFits:(CGSize)size {
    CGSize textSize = [self.textLabel sizeThatFits:size];
    CGSize contentSize = size;
    contentSize.width = MIN( size.width, textSize.width );

    return contentSize;
}

@end
3
highmaintenance

J'ai essayé la réponse de aopsfan mais cela n'a pas fonctionné. Un point d'arrêt a révélé que le centre de la barre était "(480.0, 22.0)" (la coordonnée X est complètement éteinte).

Alors je l'ai changé en ceci:

- (void)layoutSubviews 
{
    [super layoutSubviews];

    // Center Title View

    UINavigationItem* item = [self topItem]; // (Current navigation item)

    [item.titleView setCenter:CGPointMake(160.0, 22.0)]; 
    // (...Hard-coded; Assuming portrait iPhone/iPod touch)

}

... et ça marche comme un charme. L'effet de glissement/fondu lorsque vous appuyez sur les contrôleurs de vue est intact. (iOS 5.0)

2
Nicolas Miari

J'ai eu le même problème.  enter image description here Ma solution est de masquer le bouton Précédent, puis d'ajouter votre propre implémentation. Puisque le système réservera de l'espace pour les éléments de gauche.

UIImage* cancelIcon = [UIImage imageNamed:@"ic_clear"];
UIBarButtonItem* cancelButton = [[UIBarButtonItem alloc] initWithImage:cancelIcon style:UIBarButtonItemStylePlain target:self action:@selector(back:)];

et le sélecteur est simple

- (void)back:(UIButton *) sender
{
    [self.navigationController popViewControllerAnimated:YES];
}

maintenant cela ressemble à ceci:  enter image description here

oh ... et n'oubliez pas d'utiliser autolayout dans votre vue de titre personnalisée si vous avez un contenu de longueur dynamique comme label. J'ajoute une mise en page supplémentaire dans la vue personnalisée pour lui donner le style "wrap_content" dans Android en le définissant centré sur parent, ainsi que l'espace de début et fin "> =" 0 

 enter image description here

1
Nevin Chen

J'ai eu une situation similaire où une titleView devrait être centré dans UINavigationBar. J'aime l'approche d'occulus consistant à sous-classer un UIView et à surcharger setFrame:. Ensuite, je peux centrer le cadre dans les dimensions de UINavigationBar.

Dans la sous-classe UIView:

-(void)setFrame:(CGRect)frame{
  super.frame = CGRectMake(320 / 2 - 50, 44 / 2 - 15, 100, 30);
}

La sous-classe UIView peut ensuite être affectée normalement à titleView pour chaque élément de navigation. Le développeur n'a pas besoin d'ajouter et de supprimer par programme des sous-vues spéciales de UINavigationBar.

0
Richard H Fung