【问题标题】:iOS 11 navigationItem.titleView Width Not SetiOS 11 navigationItem.titleView 宽度未设置
【发布时间】:2017-12-09 11:13:56
【问题描述】:

在 iOS11 上看到一个带有 navigationItem.titleView 的行为,其中 titleView 的宽度不是屏幕的全宽。

我有一个自定义视图,我设置为 titleView。在 iOS11 之前,视图将填充导航栏区域。但是 iOS 11 并没有调整大小来填充屏幕的宽度。

我在设置 titleView 之前尝试设置视图的框架,但没有运气。我也尝试将 titleViews 超级视图强制为布局约束,但没有运气。

附上截图:

iOS10:

iOS11:

还有其他人经历过这种情况吗?

【问题讨论】:

    标签: ios uinavigationcontroller uinavigationbar ios11 navigationitem


    【解决方案1】:

    我想通了。我必须覆盖视图和文本字段的 intrinsicContentSize getter。

    我将宽度设置为 CGFloat.greatestFiniteMagnitude,因此它始终与屏幕一样宽。

    更新:

    由于我已经在这个问题上花费了几个小时,希望其他人能够通过将所有事情紧密结合起来更快地赶上来

    我创建了TitleView 的自定义子类,称为CustomTitleView,代码如下:

    import UIKit
    
    class CustomTitleView: UIView {
    
      override var intrinsicContentSize: CGSize {
        return UIView.layoutFittingExpandedSize
      }
    }
    

    我从一开始就错过的最重要的部分是:

    【讨论】:

    • 作为解释:titleView 现在使用自动布局进行布局。因为它寻找内在内容大小,所以这是有效的。
    • 可以在大标题视图下方显示标题视图吗?我为标题视图分配了一个segmentedControl,它总是显示在大标题上。
    • @Arco:你的问题解决了吗?我有同样的问题 UISegmentedControl 放在 TitleView 中并且触摸没有响应,重新附加和子类化 TitleViewUIView 类,它覆盖了 intrinsicContentSize 属性作为 João Nunes 中提到的下面的答案。
    • @el.severo 我没有解决我的问题,因为我认为没有公共 api 供我们在大型标题视图位置分配自定义视图。也许你可以看到导航栏子视图的结构并尝试使用 Objective-C 运行时来解决你的问题。
    • 问题是它还推开屏幕左右导航按钮
    【解决方案2】:

    使用@falkon 的答案是代码:

    将此代码添加到用作titleView的视图中

    override var intrinsicContentSize: CGSize {
        return UILayoutFittingExpandedSize
    } 
    

    【讨论】:

    • 已修复,但有时标题视图会在挥舞动画后移动到状态栏下方。
    • 我还必须在该视图中添加translatesAutoresizingMaskIntoConstraints = false
    【解决方案3】:

    通过创建 UIView 的子类并将其分配给 UINavigationController 的标题视图来修复它

    目标-C:

    #import "FLWCustomTitleView.h"
    
    @implementation FLWCustomTitleView
    
    - (CGSize )intrinsicContentSize {
      return UILayoutFittingExpandedSize;
    }
    
    @end
    

    【讨论】:

    • 你是如何在那里添加自定义视图的?
    【解决方案4】:

    intrinsicContentSize 设置为UILayoutFittingExpandedSize 也可以正常工作

    【讨论】:

      【解决方案5】:

      我必须将 UIImageView 设置为 navigationItem.titleView。纵横比确实合适,但intrinsicContentSize 使它变大了。 缩放图像会导致图像质量不佳。 设置布局锚对我有用:

      UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 80, 30)];
      [imageView setImage:image];
      [imageView.widthAnchor constraintEqualToConstant:80].active = YES;
      [imageView.heightAnchor constraintEqualToConstant:30].active = YES;
      [imageView setContentMode:UIViewContentModeScaleAspectFit];
      self.navigationItem.titleView = imageView;
      

      【讨论】:

        【解决方案6】:

        现有答案的补充:

        如果您的自定义标题视图是默认情况下已经具有固有内容大小的视图(.zero 除外),例如 UILabelUITextViewUIButton,您可以简单地设置

        yourCustomTitleView.translatesAutoresizingMaskIntoConstraints = false
        

        它会自动调整为仅包含其内容,但不会与左右项目视图重叠。


        例如,您可以在 Interface Builder 中将一个按钮拖到导航栏的标题视图区域中,然后在您的视图控制器中为它创建一个插座 titleButton,然后这样做

        override func viewDidLoad() {
            super.viewDidLoad()
            titleButton.translatesAutoresizingMaskIntoConstraints = false
        }
        

        【讨论】:

          【解决方案7】:

          Swift 4.2 版本的Yedy's answer

          let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 80, height: 30))
          imageView.image = image
          imageView.widthAnchor.constraint(equalToConstant: 80).isActive = true
          imageView.heightAnchor.constraint(equalToConstant: 30).isActive = true
          imageView.contentMode = .scaleAspectFit
          navigationItem.titleView = imageView
          

          Swiftify 的帮助下转换。

          【讨论】:

            【解决方案8】:

            最重要的是你需要覆盖customTitleView作为你的titleView:

            self.navigationItem.titleView = [self titleView];

            #pragma mark - getter
            
            - (UIView *)titleView {
                UIView *navTitleView = [HFCalenderTitleView new];
                navTitleView.frame = CGRectMake(0.0, 0.0, HorizontalFrom750(200.0), 44.0);
            
                [navTitleView addSubview:self.titleLabel];
                [self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
                    make.center.equalTo(navTitleView);
                }];
            
                CGFloat btnWidth = 30.0;
                [navTitleView addSubview:self.previousButton];
                self.previousButton.imageEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, 0.0, 15.0);
                [self.previousButton mas_makeConstraints:^(MASConstraintMaker *make) {
                    make.left.equalTo(navTitleView);
                    make.top.bottom.equalTo(navTitleView);
                    make.width.equalTo(@(btnWidth));
                }];
                [navTitleView addSubview:self.nextBtn];
                self.nextBtn.imageEdgeInsets = UIEdgeInsetsMake(0.0, 15.0, 0.0, 0.0);
                [self.nextBtn mas_makeConstraints:^(MASConstraintMaker *make) {
                    make.right.equalTo(navTitleView);
                    make.top.bottom.equalTo(navTitleView);
                    make.width.equalTo(@(btnWidth));
                }];
            
                return navTitleView;
            }
            #pragma mark - customTitleView
            
            #import "HFCalenderTitleView.h"
            @implementation HFCalenderTitleView
            - (CGSize)intrinsicContentSize{
                return CGSizeMake(HorizontalFrom750(200.0), 40); // the target size
            }
            

            【讨论】:

              【解决方案9】:

              当您在 CustomTitleView 中有 UIView 作为子视图时,intrinsicContentSize 解决方案不起作用,仅适用于 iOS 11 中的 XCODE 9。所以我确实喜欢下面,对我来说很好,这可能对某人有帮助。

              @interface CustomTitleView : UIView
              @property (weak, nonatomic) IBOutlet UIView *doubleTitleView;
              @end
              
              @implementation CustomTitleView
              - (void)awakeFromNib {
                  [super awakeFromNib];
                  int width = _doubleTitleView.frame.size.width;
                  int height = _doubleTitleView.frame.size.height;
                  if (width != 0 && height != 0) {
              
                      NSLayoutConstraint *widthConstraint =  [_doubleTitleView.widthAnchor constraintEqualToConstant:width];
                      NSLayoutConstraint *heightConstraint = [_doubleTitleView.heightAnchor constraintEqualToConstant:height];
              
                      [_doubleTitleView addConstraint:heightConstraint];
                      [_doubleTitleView addConstraint:widthConstraint];
                      [heightConstraint setActive:TRUE];
                      [widthConstraint setActive:TRUE];
                  }
              }
              

              【讨论】:

                【解决方案10】:

                如果您不想覆盖intrinsicContentSize,也可以使用约束。这是 SnapKit 的演示

                self.navigationItem.titleView = titleView
                if #available(iOS 11, *) {
                    titleView.snp.makeConstraints({ (make) in
                        make.width.equalTo(250) // fixed width
                        make.height.equalTo(30) // less than 44(height of naviagtion bar)
                    })
                }else {
                    titleView.frame = ...
                }
                

                但是如果任一侧(左侧或右侧)导航栏有多个navigationbaritems,则应使用intrinsicContentSize;

                【讨论】:

                • 你知道为什么需要小于 44 吗?我尝试更大但没有成功。
                【解决方案11】:

                这个类可以解决问题。确保将自定义视图的类设置为这个:

                import UIKit
                
                class TitleView: UIView {
                
                    override init(frame: CGRect) {
                        super.init(frame: frame)
                        translatesAutoresizingMaskIntoConstraints = false
                    }
                
                    required init?(coder: NSCoder) {
                        super.init(coder: coder)
                        translatesAutoresizingMaskIntoConstraints = false
                    }
                
                    override var intrinsicContentSize: CGSize {
                        CGSize(width: UIView.layoutFittingExpandedSize.width, height: self.bounds.height)
                    }
                
                }
                

                【讨论】:

                  【解决方案12】:

                  我遇到了同样的问题,但将UIImage 设置为navigationItem titleView

                  我所做的是使用以下方法将图像缩放到所需的大小:

                  -(UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize {
                  
                      UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
                      [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
                      UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
                      UIGraphicsEndImageContext();
                  
                      return newImage;
                  }
                  

                  并调用如下:

                  -(void)setHeaderImage{
                      UIImage * image = [self imageWithImage:[UIImage imageNamed:@"headerImage"] scaledToSize:CGSizeMake(150, 27)];
                      UIImageView *  imageView = [[UIImageView alloc]initWithImage:image];
                      imageView.frame = CGRectMake(0, 0, 150, 27);
                      imageView.contentMode = UIViewContentModeScaleAspectFit;
                      self.navigationItem.titleView = imageView;
                  }
                  

                  【讨论】:

                  • imageView.frame = CGRectMake(0, 100, 150, 27);是否可以在其框架中更改 Y ?
                  • 您可以将 UIImageView 放在 UIView 中并更改 UIImageView 框架
                  【解决方案13】:

                  return UILayoutFittingExpandedSize 没有帮助我,因为视图被垂直添加了几次以填充布局。

                  解决方案是将自定义视图设置宽度中的intrinsicContentSize 覆盖为最大屏幕宽度:

                   - (CGSize)intrinsicContentSize {
                      //fills empty space. View will be resized to be smaller, but if it is too small - then it stays too small
                      CGRect frame = self.frame;
                      frame.size.width = MAX(SCREEN_WIDTH, SCREEN_HEIGHT);
                      return frame.size;
                  }
                  

                  【讨论】:

                    【解决方案14】:

                    尝试使用标准 UISearchBar / UISearchController

                    实际上,您需要做的 - 如果您可以使用标准 UISearchBar / UISearchController 以以下方式显示搜索栏,该方式尊重安全区域,因此在 iPhone X 和每个设备方向上看起来都很完美:

                    func presentSearchController() {
                        let searchController = UISearchController(searchResultsController: nil)
                        searchController.searchResultsUpdater = self
                        searchController.obscuresBackgroundDuringPresentation = false
                        searchController.searchBar.text = "any text"
                    
                        if #available(iOS 11.0, *) {
                            self.navigationItem.searchController = searchController
                            searchController.isActive = true
                        } else {
                            present(searchController, animated: true, completion: nil)
                        }
                    }
                    

                    参考文献

                    https://developer.apple.com/videos/play/fall2017/201/ https://medium.com/@PavelGnatyuk/large-title-and-search-in-ios-11-514d5e020cee

                    【讨论】:

                      【解决方案15】:

                      设置导航控制器时

                      您只需将 translatesAutoresizingMaskIntoConstraints 设置为 false check apple doc

                      请注意,自动调整掩码约束完全指定了视图的大小和位置;因此,您不能添加额外的约束来修改此大小或位置而不引入冲突。如果要使用 Auto Layout 来动态计算视图的大小和位置,则必须将此属性设置为 false

                      然后将其分配给您想要的宽度

                      navigationItem.titleView?.translatesAutoresizingMaskIntoConstraints = false
                      
                      lazy var titleWidth =  view.frame.size.width / 2
                      
                      navigationItem.titleView?.constrainWidth(constant: titleWidth)
                      

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 2013-09-28
                        • 1970-01-01
                        • 1970-01-01
                        • 2017-04-06
                        • 2018-03-17
                        • 2013-07-22
                        • 1970-01-01
                        • 1970-01-01
                        相关资源
                        最近更新 更多