Подтвердить что ты не робот

Настройка рамки navigationItem.titleView?

Я заметил, что позиция titleView зависит от названия правой панели. Как я могу установить рамку titleView в центре вместо этого?

Я попытался установить titleView.frame, но безрезультатно.

Здесь код:

UIButton *titleLabel = [UIButton buttonWithType:UIButtonTypeCustom];
[titleLabel setTitle:@"Right Eye" forState:UIControlStateNormal];
[titleLabel setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[titleLabel setTitleColor:[UIColor blackColor] forState:UIControlStateHighlighted];
titleLabel.frame = CGRectMake(100, 0, 180, 44);
titleLabel.titleLabel.backgroundColor = [UIColor clearColor];
titleLabel.titleLabel.font = [UIFont boldSystemFontOfSize:20.0];
titleLabel.titleLabel.shadowColor = [UIColor colorWithWhite:0.0 alpha:0.3];
//  titleLabel.titleLabel.textAlignment = UITextAlignmentCenter; (this doesn't work either)
[titleLabel addTarget:self action:@selector(titleTap:) forControlEvents:UIControlEventTouchUpInside];
self.navigationItem.titleView = titleLabel;
self.navigationItem.titleView.frame = CGRectMake(100, 0, 180, 44); //(this doesn't work either)

alt text

4b9b3361

Ответ 1

Иногда между вашим представлением контроллера viewWillAppear: и viewDidAppear: панель навигации перемещает ваш заголовок и изменяет его размер, если необходимо. Он может оказаться невключенным, потому что панель навигации предпочитает не изменять размер titleView для соответствия между кнопками. Кажется, он пытается сосредоточить заголовок, если он достаточно мал, но если не будет перемещать ваш titleView не по центру, и тогда я думаю, что только в качестве последнего средства будет изменяться. Эффект заключается в том, что titleView занимает все пространство между двумя кнопками, если его textAlignment центрируется, то он будет центрироваться в этом пространстве, но не в центре по отношению ко всему экрану. Вы можете видеть это на снимке экрана.

Один из ответов заключается в том, чтобы сделать ваш заголовок более узким, чтобы панель навигации могла центрировать его, поэтому попробуйте около 160 вместо 180, когда вы установите свой заголовок. Это отстойно, что при создании представления программно, как и вы, нужно поместить оценку этой ширины в код. Что было бы хорошо - это способ максимизировать это пространство, оставаясь в центре.

Можно начинать с того, что titleView является шириной экрана, после чего на панели навигации изменяется titleView.frame, обновите его снова в представлении контроллера viewDidAppear:. Используя отредактированные titleView.frame.origin.x и size.width вместе с шириной экрана, вы можете вычислить наибольшее из левого и правого полей, а затем установите для начала origin.x значение width.width на ширину экрана минус это время 2. Однако это не вступает в силу до тех пор, пока после того, как оживленный вид не оживится, и сдвиг впоследствии будет виден. Вы можете скрыть заголовок в viewWillAppear: затем показать в viewDidAppear: после его центрирования, вместо того, чтобы сдвигаться с нецентральным titleView, который затем сдвигается, он будет скользить без заголовка, который затем появляется.

Лучше всего сделать свой заголовокНайти свой собственный подкласс UIView (или UILabel или любой другой) и переопределить setFrame, чтобы изменить его размер, чтобы оставаться в центре его супервизора. Если я когда-нибудь закончу это, я отправлю его здесь. Или, может быть, кто-то еще знает другое место, чтобы изменить кадр titleView после его обновления, но перед тем, как представление соскальзывает без подкласса вида.

Ответ 2

После настройки titleView или titleLabel вызовите sizeToFit на нем, также убедитесь, что titleLabel.textAlignment = UITextAlignmentCenter. Он будет располагаться по ширине навигационной панели, а не в промежутке между краем кнопки и дальним краем навигатора.

Ответ 3

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

Я закончил работу над идеей smallduck и переопределив setFrame, был прост как:

- (void)setFrame:(CGRect)frame {
    [super setFrame:CGRectMake(0, 0, self.superview.bounds.size.width, self.superview.bounds.size.height)];
}

Ответ 4

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

UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];    
label.text = @"Title";
[label sizeToFit];
self.navigationItem.titleView = label;

Ответ 5

-(void) awakeFromNib
{
    UIButton *titleLabel = [UIButton buttonWithType:UIButtonTypeCustom];
    [titleLabel setTitle:@"Right Eye" forState:UIControlStateNormal];
    [titleLabel setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    [titleLabel setTitleColor:[UIColor blackColor] forState:UIControlStateHighlighted];
    titleLabel.titleLabel.backgroundColor = [UIColor clearColor];
    titleLabel.titleLabel.font = [UIFont boldSystemFontOfSize:20.0];
    titleLabel.titleLabel.shadowColor = [UIColor colorWithWhite:0.0 alpha:0.3];
    [titleLabel addTarget:self action:@selector(titleTap:) forControlEvents:UIControlEventTouchUpInside];
    titleLabel.frame = CGRectMake(0, 0, 400, 20);
    self.navigationItem.titleView = titleLabel;

}

Ответ 6

Мое решение состояло в том, чтобы вручную изменить размер панели навигации в viewDidAppear:

- (void)viewDidAppear
{
     [super viewDidAppear];
     [self.navigationController.navigationBar setFrame:CGRectMake(x, y, width, height)];
}

... после этого вы также можете изменить положение заголовка. Я только заметил, что основной проблемой был тот факт, что навигационная панель также изменилась, поэтому я вернул ее в обычный размер. Я получил регулярный размер от отладки и проверки его размера в viewDidLoad, прежде чем он изменился...

Ответ 7

Такая же проблема. Реализация автопрокрутки в качестве titleView. Таким образом, чтобы длинный текст в заголовке навигации можно было автоматически прокручивать, чтобы пользователь мог его просмотреть. Все проблемы с неизвестными реальными размерами titleView предотвращают центрирование текста в простейшем частном случае: когда текст меток подходит и нет необходимости в автопрокрутке (например, задание свойства title to titleItem).

Ответ 8

У меня есть немного другой вариант использования (вертикальное смещение UIButton как titleView на iOS 7). После долгого времени я придумал использование свойства contentEdgeInsets UIButton для смещения содержимого в его кадре.

Ответ 9

Только так, как я нашел, исправить это, чтобы не использовать UINavigationItems. Insted использует два разных вида на стороне кнопки eace UINavigationBar, например:

-(UIView *)rightButtonViewSection {
    if (!_rightButtonViewSection) {

        _rightButtonViewSection = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 80, 45)];

    }
    return _rightButtonViewSection;

}

-(UIView *)leftButtonViewSection {
    if (!_leftButtonViewSection) {

        _leftButtonViewSection = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 80, 45)];

    }
    return _leftButtonViewSection;

}

и setButtons на нем так:

 ButtonBase *searchButton = [[ButtonBase alloc] initWithFrame:CGRectMake(0, 0, 32, 30)];
    [searchButton setImage:[UIImage imageNamed:SEARCH_IMAGE] forState:UIControlStateNormal];
    SEL searchSelector = @selector(tradersSearchButtonPress);
    [searchButton addTarget:self action:searchSelector forControlEvents:UIControlEventTouchUpInside];

    self.notificationButton.view.frame = [self rightButtonFrame];
    searchButton.frame = [self rightSecoundButtonFrame];

    [self.rightButtonViewSection removeAllSubviews];
    [self.rightButtonViewSection addSubview:self.notificationButton.view];
    [self.rightButtonViewSection addSubview:searchButton];

    UIBarButtonItem *buttonItem  = [[UIBarButtonItem alloc] initWithCustomView:self.rightButtonViewSection];
    self.topViewController.navigationItem.rightBarButtonItem = buttonItem;

ButtonsFrames:

-(CGRect) rightButtonFrame {
    return CGRectMake(self.rightButtonViewSection.width - 32, 7, 32, 30);
}
-(CGRect) rightSecoundButtonFrame {
    return CGRectMake(self.rightButtonViewSection.width - 80, 7, 32, 30);
}

Тогда название не будет двигаться! потому что UIButtonsViews имеют одинаковую ширину.

Ответ 10

Я использовал двухстрочный заголовок, похожий на то, что делает WhatsApp (название и субтитры).

Я исправил эту проблему путем подклассификации UINavigationController и переопределения viewDidLayoutSubviews().

My titleView выглядит следующим образом (в viewController):

let frame = self.navigationController?.navigationBar.bounds ?? CGRect.zero

// This is a container view for the two labels, laying them out vertically
let titleView = UIStackView(arrangedSubviews: [self._titleLabel, self._promptLabel])
titleView.axis = .vertical
titleView.alignment = .center
titleView.distribution = .fill
titleView.frame = frame // set the frame to the navbarFrame initially
titleView.spacing = 0

// The wrapper is necessary for laying out the stackView as the titleView
let wrapperView = UIView(frame: frame)
wrapperView.addSubview(titleView)

self.navigationItem.titleView = wrapperView

Мой viewDidLayoutSubviews():

guard let navigationItem = self.topViewController?.navigationItem,
      let titleView = navigationItem.titleView,
      let wrapperView = titleView.subviews[0] as? UIStackView else { return }

var width : CGFloat = 0

for view in wrapperView.arrangedSubviews {
    view.sizeToFit()
    width = max(width, view.frame.size.width)
}

titleView.frame.size.width = width
titleView.frame.size.height = self.navigationBar.frame.height
wrapperView.frame = titleView.bounds
wrapperView.center.x = self.navigationBar.convert(self.navigationBar.center, to: titleView).x
wrapperView.center.y = titleView.frame.height / 2

self.navigationBar.layoutIfNeeded()

Примечание: Хитрость заключается в том, чтобы иметь вид оболочки вокруг вашего titleView, который может быть выложен на панели навигации. Затем отрегулируйте рамку вашего titleView так, чтобы вы хотели.

Ответ 11

В последнее время я сталкиваюсь с той же проблемой, у меня есть сложный заголовок, содержимое которого может меняться, поэтому я хочу показать как можно больше контента, мой элемент левой кнопки и элемент кнопки правой панели имеют разную ширину, поэтому, если я установите его на большую ширину, панель навигации не будет центрировать его. Как вы можете знать, когда элемент кнопки с левым или правым баром очень длинный, невозможно центрировать заголовок, поэтому я хочу как можно больше центрировать его.

Как только мы установим представление на self.navigationItem.titleView, панель навигации будет управлять рамкой представления заголовка, ее трудно сосредоточить непосредственно, поэтому я подклассифицирую представление, которое работает как представление контейнера реального заголовка заголовка, я устанавливаю его ширину с помощью ширину экрана, UINavigationBar с установкой его рамки в значение свойства, относящееся к его элементу левой/правой панели.

Вид контейнера MDLNavigationTitleContainer, а реальное название заголовка MDLMessagesNavigationTitleView, MDLMessagesNavigationTitleView управляется с помощью автоматического макета, так как его супер-просмотр MDLNavigationTitleContainer, каждый раз, когда изменяется его ширина, layoutSubviews, Код в layoutSubviews кажется немного странным, он используется для обработки анимации push/pop.

@interface MDLNavigationTitleContainer ()

@property (nonatomic) CGRect oldFrame;

@end

@implementation MDLNavigationTitleContainer

- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        UINib *nib = [UINib nibWithNibName:@"MDLMessagesNavigationTitleView" bundle:[NSBundle bundleForClass:[MDLMessagesNavigationTitleView class]]];
        self.titleView = [[nib instantiateWithOwner:nil options:nil] firstObject];
        self.titleView.translatesAutoresizingMaskIntoConstraints = NO;
        [self addSubview:self.titleView];
        NSLayoutConstraint *centerX = [NSLayoutConstraint constraintWithItem:self.titleView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1 constant:0];
        NSLayoutConstraint *centerY = [NSLayoutConstraint constraintWithItem:self.titleView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1 constant:0];
        NSLayoutConstraint *width = [NSLayoutConstraint constraintWithItem:self.titleView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationLessThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:0];
        width.priority = 200;
        NSLayoutConstraint *width1 = [NSLayoutConstraint constraintWithItem:self.titleView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationLessThanOrEqual toItem:self attribute:NSLayoutAttributeWidth multiplier:1 constant:0];
        [self addConstraint:centerX];
        [self addConstraint:centerY];
        [self addConstraint:width];
        [self addConstraint:width1];
    }
    return self;
}

- (void)layoutSubviews {
    [super layoutSubviews];

    if (!self.superview) {
        return;
    }

    if (self.center.x > [UIScreen mainScreen].bounds.size.width) {
        self.titleView.frame = self.oldFrame;
        return;
    }

    CGFloat centerX = self.center.x;

    CGFloat superWidth = [UIScreen mainScreen].bounds.size.width;
    CGFloat superCenterX = superWidth/2;
    CGFloat offsetX = superCenterX - centerX;
    CGPoint center = self.titleView.center;

    if (CGRectGetMaxX(self.titleView.frame) + offsetX < self.bounds.size.width &&
        CGRectGetMinX(self.titleView.frame) + offsetX > 0) {
        center = CGPointMake(self.bounds.size.width/2 + offsetX, self.bounds.size.height/2);
    }
    CGSize size = self.titleView.bounds.size;
    if (size.width > self.bounds.size.width) {
        size.width = self.bounds.size.width;
    }

    self.titleView.frame = CGRectMake(center.x-size.width/2, center.y-size.height/2, size.width, size.height);
    self.oldFrame = self.titleView.frame;
}

Задайте название:

MDLNavigationTitleContainer *titleView = [[MDLNavigationTitleContainer alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 44)];
self.navigationItem.titleView = titleView;

Ответ 12

Просто добавьте невидимую кнопку (без текста) в правую сторону панели навигации и измените ее размер, например, на 20 пикселей