【问题标题】:UINavigationItem centering the titleUINavigationItem 居中标题
【发布时间】:2023-03-14 00:26:01
【问题描述】:

我有一个导航栏,每侧都有左右栏按钮。我有一个customTitlelabel,我将它设置为UINavigationItem 的titleView。

[self.navigationItem setTitleView:customTitleLabel];

现在一切都很好。问题是,rightbarButton 的大小是动态的,基于我在其中一个文本字段中获得的输入。

因此,标题会根据按钮之间的可用空间自动居中。

如何将标题设置为固定位置?

【问题讨论】:

    标签: iphone ios uinavigationcontroller uinavigationitem


    【解决方案1】:

    设置导航栏的 titleView 属性可以正常工作 - 无需继承或更改自定义视图以外的任何框架。

    使其相对于 UINavigationBar 的整体宽度居中的技巧是:

    1. 根据文本大小设置视图宽度
    2. 将对齐方式设置为居中并
    3. 设置自动调整掩码,使其大小调整到可用空间

    下面是一些示例代码,它创建了一个带有标签的自定义 titleView,该标签​​在 UINavigationBar 中保持居中,而与方向、左或右 barbutton 宽度无关:

    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;
    

    【讨论】:

    • 当标题的长度大于 25 个字符时,我还使它与设置较小字体和 numberOfLines = 2 的两行标题一起使用。这样你就有了一个多行标题标签。
    • 另外,忘了说在desiredWidth的计算中,代码可能应该引用titleHeight而不是titleLabel.frame.size.height,由于CGRectZero构造,它将为零。
    • 很好的答案!为我节省了大量时间
    • 对我不起作用 (iOS7,8)。只是复制标准的标题行为。好的,另外允许标题是多行的。但是尽管有问题询问的左右按钮的宽度,但不会将标题固定到导航栏中心。
    • 仅供参考 - 在 iOS 7 之后无法执行:'size(with:constrainedTo:lineBreakMode:)' 在 iOS 中不可用:从 iOS 7 及更早版本开始弃用的 API 在 Swift 中不可用
    【解决方案2】:

    你不能直接做你想做的事——你的标题视图的位置是你无法控制的(当由UINavigationBar 管理时)。

    但是,至少有两种策略可以达到你想要的效果:

    1) 添加标题视图不是作为导航栏的“正确”标题视图,而是作为UINavigationBar 的子视图。 (注意:这不是“官方”批准的,但我已经看到它完成了,并且有效。显然你必须注意你的标题标签覆盖按钮的位,并为不同的方向处理不同大小的导航栏等。 -- 有点繁琐。)

    2) 创建一个智能 UIView 子类,在计算出的位置显示给定子视图(这将是您的 UILabel),以有效地显示子视图在屏幕上完美居中。为此,您的智能 UIView 子类将通过更改标签子视图的位置 (frame) 来响应布局事件(或 frame 属性更改等)。

    就个人而言,我最喜欢方法 2) 的想法。

    【讨论】:

      【解决方案3】:
      override func viewDidLoad() {
          super.viewDidLoad()
          navigationController?.navigationBar.topItem?.title = ""
      }
      
      override func viewWillAppear(animated: Bool) {
          super.viewWillAppear(animated)
          navigationItem.title = "Make peace soon"
      }
      

      【讨论】:

      • 尽管左右按钮的宽度不同,您真的认为此解决方案会将标题固定在导航栏中心吗?
      • 我不知道为什么会这样......但确实如此!如果有人能解释原因,将不胜感激。
      • 我认为这与视图生命周期有关。 viewDidLoad 在 vi​​ewWillLayout 之前被调用,所以基本上他把它变成了一个不占用大小的空字符串。因此,当调用 viewWillLayout 时,它会将标题的大小调整为几乎为零。然后在布局完成后发生的 viewWillAppear 中,他添加了他真正想要的内容。之后没有重新布局。
      • 这很好用。但它会缩小默认后退按钮的宽度
      【解决方案4】:

      正确的答案是覆盖自定义titleViewsizeThatFits: 并返回其内容大小。导航栏居中自定义标题视图,直到没有剩余空间。

      例如,如果您有 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
      

      【讨论】:

      • 你能澄清你的答案吗?请注意,问题是关于将标题视图相对于整个导航栏宽度水平居中,而不仅仅是在分配的空间内。
      【解决方案5】:

      我尝试了 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)

      【讨论】:

        【解决方案6】:

        我有类似的问题。 我的解决方案是隐藏原来的后退按钮,添加你自己的实现。因为系统会为剩下的物品预留空间。

        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];
        }
        

        现在看起来像这样:

        哦...如果您有动态长度内容(如标签),请不要忘记在自定义标题视图中使用自动布局。我在 customview 中添加了一个额外的布局,通过将其设置为 parent 居中以及前导和尾随空格 ">=" 0

        来赋予它类似于 Android 中的“wrap_content”

        【讨论】:

          【解决方案7】:

          我遇到过类似的情况,titleView 应该位于 UINavigationBar 的中心。我喜欢 Oculus 将 UIView 子类化并覆盖 setFrame: 的方法。然后,我可以在 UINavigationBar 的尺寸内将框架居中。

          在 UIView 子类中:

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

          UIView 子类可以正常分配给每个导航项的titleView。开发人员不必以编程方式从 UINavigationBar 添加和删除特殊子视图。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2014-09-10
            • 2011-03-08
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-06-06
            相关资源
            最近更新 更多