UINavigationItem центрирование заголовка - PullRequest
20 голосов
/ 24 ноября 2011

У меня есть панель навигации с кнопками панели слева и справа на каждой стороне.У меня есть customTitlelabel, который я установил в качестве titleView UINavigationItem.

[self.navigationItem setTitleView: customTitleLabel];

Теперь все в порядке.Проблема в том, что размер правой кнопки мыши является динамическим в зависимости от ввода, которое я получаю в одном из текстовых полей.

Поэтому заголовок автоматически центрируется на основе свободного пространства между кнопками.

как установить заголовок на фиксированную позицию?

Ответы [ 7 ]

28 голосов
/ 14 февраля 2012

Настройка свойства titleView панели навигации работает просто отлично - не нужно создавать подклассы или изменять какие-либо кадры, кроме тех, что у вас в пользовательском представлении.

Хитрость в том, чтобы выровнять его относительно общей ширины UINavigationBar, заключается в следующем:

  1. установите ширину вашего вида в соответствии с размером текста
  2. установить выравнивание по центру и
  3. установить маску авторазмера, чтобы она изменялась в соответствии с доступным пространством

Вот пример кода, который создает пользовательский titleView с меткой, которая остается в центре UINavigationBar независимо от ориентации, ширины левой или правой кнопки:

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;
15 голосов
/ 25 ноября 2011

Вы не можете делать то, что вы хотите напрямую - положение вашего представления заголовка находится вне вашего контроля (когда управляется UINavigationBar).

Однако есть по крайней мере две стратегии для получения желаемого эффекта:

1) Добавьте представление заголовка не как «правильный» заголовок панели навигации, а как подпредставление.из UINavigationBar.(Примечание: это не «официально» санкционировано, но я видел, что это сделано, и работает. Очевидно, вы должны следить за битами перезаписи метки заголовка кнопок и обрабатывать навигационные панели разных размеров для разных ориентаций и т. Д.).- немного неудобно.)

2) Создайте интеллектуальный подкласс UIView, который отображает заданное подпредставление (которое будет вашей UILabel) в позиции, рассчитанной для эффективного отображения подпредставления, идеально центрированного на экране.Для этого ваш интеллектуальный подкласс UIView будет реагировать на события макета (или frame изменения свойств и т. Д.), Изменяя положение (frame) подпредставления метки.

Лично мне нравитсяИдея подхода 2) лучшее.

12 голосов
/ 27 августа 2015
override func viewDidLoad() {
    super.viewDidLoad()
    navigationController?.navigationBar.topItem?.title = ""
}

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    navigationItem.title = "Make peace soon"
}
3 голосов
/ 02 ноября 2014

Правильный ответ - переопределить sizeThatFits: вашего пользовательского titleView и вернуть размер его содержимого. Панель навигации центрирует пользовательский вид заголовка, пока для этого не останется свободного места.

Например, если у вас есть UIView контейнер с UILabel внутри:

@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
2 голосов
/ 11 мая 2012

Я попробовал ответ Aopsfan, но он не сработал.Точка останова показала, что центр бара был "(480.0, 22.0)" (координата X удалена).

Поэтому я изменил его на следующее:

- (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)

}

... и этоработает как шарм.Эффект слайда / затухания при нажатии на контроллеры вида не поврежден.(iOS 5.0)

1 голос
/ 23 августа 2016

У меня была похожая проблема.enter image description here Мое решение - скрыть исходную кнопку возврата, добавить добавить собственную реализацию.Поскольку система зарезервирует место для левых элементов.

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

, а селектор прост

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

, теперь он выглядит так: enter image description here

о ... и не забудьте использовать autolayout в вашем пользовательском представлении заголовка, если у вас есть содержимое с динамической длиной, например, с надписью.Я добавляю дополнительный макет в пользовательском представлении, чтобы он выглядел как «wrap_content» в Android, устанавливая его по центру родительского, а также начальный и конечный пробел »> =« 0

enter image description here

0 голосов
/ 29 октября 2013

У меня была похожая ситуация, когда titleView должен быть в центре UINavigationBar. Мне нравится подход Occulus подкласса UIView и переопределение setFrame:. Затем я могу центрировать рамку внутри размеров UINavigationBar.

В подклассе UIView:

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

Подкласс UIView затем может быть назначен как правило titleView для каждого элемента навигации. Разработчику не нужно программно добавлять и удалять специальные подпредставления из UINavigationBar.

...