调整navigationItem.titleView的框架?

时间:2010-09-10 02:52:58

标签: iphone uinavigationitem

我注意到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

13 个答案:

答案 0 :(得分:46)

视图控制器的viewWillAppear之间的某个时间:& viewDidAppear :,导航栏正在重新定位你的titleView并调整大小以适应它。它最终会被取消因为导航栏更喜欢不调整titleView以适应按钮之间。它似乎试图将标题视图居中,如果它足够小,但如果没有将你的titleView偏离中心,然后我认为只有最后的手段才会调整大小。结果是titleView占据了两个按钮之间的所有空间,如果它的textAlignment居中,那么它将居中于那个空间,尽管不是相对于整个屏幕居中。您可以在屏幕截图中看到这一点。

一个答案是让你的titleView更窄,以便导航栏可以居中,所以在设置titleView.frame时尝试大约160而不是180。很糟糕的是,当您以编程方式创建视图时,必须将该宽度的估计值放入代码中。什么是好的是在保持居中的同时最大化空间的方法。

可以从titleView作为屏幕宽度开始,然后在导航栏更改titleView.frame之后,在视图控制器的viewDidAppear中再次更新它:使用其调整后的titleView.frame.origin.x和size.width以及屏幕宽度,您可以计算左边和右边的最大值。右边距,然后将origin.x设置为,size.width到屏幕宽度减去那个时间2.然而,直到推动的视图已经动画化并且之后的移动可见之后,它才会生效。您可以在viewWillAppear中隐藏titleView:然后在viewDidAppear中取消隐藏:在居中后,不要使用偏离中心的titleView滑入,然后移动它,它将滑入而没有出现的标题。

更好的可能性是让你的标题查看你自己的UIView(或UILabel或其中任何一个)的子类,并覆盖setFrame来调整自身大小以保持其超级视图的中心。如果我自己最终这样做,我会在这里发布。或者也许其他人知道另一个地方在更新后更改titleView的框架,但在视图滑入之前没有视图子类。

答案 1 :(得分:17)

设置titleView或titleLabel后,请在其上调用sizeToFit,同时确保titleLabel.textAlignment = UITextAlignmentCenter。它将以导航栏的宽度为中心,而不是在导航栏的按钮边缘和远边缘之间的空间中。

答案 2 :(得分:12)

这里没有任何建议对我有用。我的问题是我在设置titleView时导航栏正处于转换的中间 - 我会得到这个奇怪的抖动,其中titleView会闪烁到左边,然后最终回到中心。

我最终遵循了smallduck的想法并重写了setFrame,就像这样简单:

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

答案 3 :(得分:6)

您可以尝试最初将帧设置为CGRectZero并调用sizeToFit。下面是我用来更改标题文本并确保它仍然居中的代码。我左边有一个后退按钮。

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

答案 4 :(得分:1)

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

}

答案 5 :(得分:1)

我的解决方案是在viewDidAppear:

中手动调整导航栏的大小
- (void)viewDidAppear
{
     [super viewDidAppear];
     [self.navigationController.navigationBar setFrame:CGRectMake(x, y, width, height)];
}

...之后你也可以重新定位标题视图。我刚刚注意到主要的问题是导航栏wqas也调整了大小,所以我把它恢复到常规尺寸。我从调试中获得了常规大小,并在修改之前在viewDidLoad中检查了它的大小...

答案 6 :(得分:0)

这里的问题相同。将自动滚动标签实现为titleView。因此,导航标题中的长文本可以自动滚动以供用户查看。 titleView的未知真实维度的所有问题都会阻止文本居中在最简单的特殊情况下:当标签文本适合并且不需要自动滚动时(例如将文本设置为navigationItem的title属性)。

答案 7 :(得分:0)

我还有一个其他用例(UIButton的垂直偏移量作为iOS 7上的titleView)。很长一段时间后,我想出了使用UIButton的contentEdgeInsets属性来移动其框架中的内容。

答案 8 :(得分:0)

我发现修复此问题的唯一方法是不使用UINavigationItems。 Insted在UINavigationBar的eace按钮侧使用两个不同的视图,如下所示:

-(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的宽度相同。

答案 9 :(得分:0)

我正在实施一个类似于WhatsApp正在做的事情的两行标题(标题和副标题)。

我通过继承UINavigationController并覆盖viewDidLayoutSubviews()来修复此问题。

我的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的框架调整为您想要的内容。

答案 10 :(得分:0)

最近我面临同样的问题,我有一个复杂的标题视图,其内容可能会发生变化,所以我希望可以显示更多的内容,我的左栏按钮项和右栏按钮项有不同的宽度,所以如果我设置它的宽度很长,导航栏不会居中。您可能知道左侧或右侧条形按钮项目的时间很长,因此无法将标题视图居中,因此我希望尽可能使其居中。

一旦我们将视图设置为self.navigationItem.titleView,导航栏将管理标题视图的框架,很难直接居中,所以我将一个视图作为真实标题视图的容器视图的子类,我设置它的宽度使用屏幕宽度UINavigationBar将其框架设置为与其左/右条形按钮项相关的属性值。

容器视图为MDLNavigationTitleContainer,真正的标题视图为MDLMessagesNavigationTitleViewMDLMessagesNavigationTitleView由自动布局管理,因为它的超级视图为MDLNavigationTitleContainer,每次宽度都是更改,layoutSubviews将被调用。 layoutSubviews中的代码似乎有点奇怪,它用于处理推/动画动画。

@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;

答案 11 :(得分:0)

在您的视图视图中覆盖-intrinsicContentSize

- (CGSize )intrinsicContentSize { return CGSizeMake(180, 44); }

答案 12 :(得分:-1)

只需在导航栏右侧添加隐藏按钮(无文字),然后将其大小更改为例如20像素