27

我注意到 titleView 的位置取决于 rightbarbutton 的标题。如何将 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)

替代文字

4

13 回答 13

46

在您的视图控制器的 viewWillAppear: 和 viewDidAppear: 之间的某个时间,导航栏正在重新定位您的 titleView 并在必要时调整它的大小以适应。它最终可能会不居中,因为导航栏不希望调整 titleView 的大小以适应按钮之间的大小。如果标题视图足够小,它似乎会尝试将其居中,但如果不是,则会将您的 titleView 移离中心,然后我认为只有在最后的手段下才会调整大小。效果是 titleView 占用了两个按钮之间的所有空间,如果它的 textAlignment 居中,那么它将在空间中居中,但不是相对于整个屏幕居中。您可以在屏幕截图中看到这一点。

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

可以一开始titleView是屏幕宽度,然后导航栏改变titleView.frame后,在view controller的viewDidAppear:中自己再更新一次。使用其调整后的 titleView.frame.origin.x 和 size.width 以及屏幕宽度,您可以计算出左右边距的最大值​​,然后将 origin.x 设置为该值,将 size.width 设置为屏幕宽度减去那个时间 2. 但是,直到推送视图动画并且之后的转变可见之后才会生效。您可以将 titleView 隐藏在 viewWillAppear: 中,然后在 viewDidAppear: 中取消隐藏,然后将其居中,因此不是使用偏离中心的 titleView 滑入然后移动,而是滑入而没有出现的标题。

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

于 2011-02-07T19:48:59.007 回答
20

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

于 2012-02-06T20:51:34.690 回答
12

这里的建议都没有真正对我有用。我的问题是我在导航栏处于过渡中间时设置了 titleView - 我会得到这个奇怪的抖动,titleView 会向左闪烁,然后最终回到中心。

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

- (void)setFrame:(CGRect)frame {
    [super setFrame:CGRectMake(0, 0, self.superview.bounds.size.width, self.superview.bounds.size.height)];
}
于 2012-05-10T23:35:03.923 回答
6

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

UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];    
label.text = @"Title";
[label sizeToFit];
self.navigationItem.titleView = label;
于 2014-03-08T04:39:14.507 回答
3

intrinsicContentSize在您的自定义视图中覆盖:

- (CGSize )intrinsicContentSize {
    return CGSizeMake(180, 44);
}
于 2018-10-25T10:33:12.713 回答
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;

}
于 2011-05-30T15:06:08.643 回答
1

我的解决方案是在 viewDidAppear 中手动调整导航栏的大小:

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

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

于 2014-01-29T11:10:33.977 回答
0

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

于 2010-11-25T17:46:18.770 回答
0

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

于 2014-03-13T14:01:04.970 回答
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;

按钮框架:

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

那么标题就不动了!因为 UIButtonsViews 的宽度相同。

于 2015-03-02T21:15:15.640 回答
0

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

我通过子类化UINavigationController和覆盖解决了这个问题viewDidLayoutSubviews()

我的 titleView 如下所示(在 a 中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 的框架调整为您想要的。

于 2017-05-23T13:41:30.853 回答
0

最近我遇到了同样的问题,我有一个复杂的标题视图,其内容可能会发生变化,所以我希望可以显示尽可能多的内容,我的左栏按钮项目和右栏按钮项目的宽度不同,所以如果我将它设置为长宽,导航栏不会居中。您可能知道,当左右栏按钮项目很长时,不可能将标题视图居中,所以我想尽可能地居中。

一旦我们将视图设置为self.navigationItem.titleView,导航栏将管理标题视图的框架,很难直接将其居中,因此我将一个视图子类化为真正的标题视图的容器视图,我将其宽度设置为屏幕宽度,UINavigationBar并设置其框架到与其左/右栏按钮项目有关的属性值。

容器视图是MDLNavigationTitleContainer,真正的标题视图是MDLMessagesNavigationTitleViewMDLMessagesNavigationTitleView由自动布局管理,因为它的超级视图是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;
于 2017-07-16T14:49:09.720 回答
-1

只需在导航栏右侧添加不可见按钮(无文本),并将其大小更改为例如 20 px

于 2015-04-02T07:55:41.277 回答