UISearchBar增加iOS 11中的导航栏高度

我有我的UISearchBar是导航栏的一部分,如:

  let searchBar = UISearchBar() //some more configuration to the search bar ..... navigationItem.titleView = searchBar 

更新到iOS 11后,我的应用程序中的search栏发生了一些奇怪的事情。 在iOS 10和之前,我有我的导航栏看起来像:

在这里输入图像说明

现在与iOS 11我有:

在这里输入图像说明

正如你所看到的那样,在两个search栏的四舍五入中有不同之处,这并不困扰我。 问题是search栏增加了导航栏的高度。 所以当我去另一个控制器时,它看起来很奇怪:

在这里输入图像说明

事实上,奇怪的黑线的高度加上当前导航栏的高度等于导航栏的高度显示在第二张图片…

任何想法如何摆脱黑线和所有视图控制器具有一致的导航栏高度?

您可以将高度为44的约束添加到iOS 11的search栏中。

 if #available(iOS 11.0, *) { searchBar.heightAnchor.constraint(equalToConstant: 44).isActive = true } 

// Objective-c

  if (@available(iOS 11.0, *)) { [searchBar.heightAnchor constraintEqualToConstant:44].active = YES; } 

我相信在iOS 11 UISearchBar现在有高度等于56,和UINavigationBar使用自动布局,以适应其子视图,因此它增加了高度。 如果你仍然想在iOS 11中使用UISearchBar作为titleView,我发现最好的方法是将UISearchBarembedded到自定义视图中,并将此视图的高度设置为44,并将其分配给navigationItem.titleView

 class SearchBarContainerView: UIView { let searchBar: UISearchBar init(customSearchBar: UISearchBar) { searchBar = customSearchBar super.init(frame: CGRect.zero) addSubview(searchBar) } override convenience init(frame: CGRect) { self.init(customSearchBar: UISearchBar()) self.frame = frame } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func layoutSubviews() { super.layoutSubviews() searchBar.frame = bounds } } class MyViewController: UIViewController { func setupNavigationBar() { let searchBar = UISearchBar() let searchBarContainer = SearchBarContainerView(customSearchBar: searchBar) searchBarContainer.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: 44) navigationItem.titleView = searchBarContainer } } 

在Objective-C中

 if (@available(iOS 11.0, *)) { [self.searchBar.heightAnchor constraintLessThanOrEqualToConstant: 44].active = YES; } 

我发现迈迈的解决scheme是唯一真正可用的解决scheme。
然而,它仍然不完美:
在旋转设备时,search栏没有正确resize,并保持较小的尺寸。

我find了一个解决办法。 这是我在Objective C中的代码,注释了相关的部分:

 // improvements in the search bar wrapper @interface SearchBarWrapper : UIView @property (nonatomic, strong) UISearchBar *searchBar; - (instancetype)initWithSearchBar:(UISearchBar *)searchBar; @end @implementation SearchBarWrapper - (instancetype)initWithSearchBar:(UISearchBar *)searchBar { // setting width to a large value fixes stretch-on-rotation self = [super initWithFrame:CGRectMake(0, 0, 4000, 44)]; if (self) { self.searchBar = searchBar; [self addSubview:searchBar]; } return self; } - (void)layoutSubviews { [super layoutSubviews]; self.searchBar.frame = self.bounds; } // fixes width some cases of resizing while search is active - (CGSize)sizeThatFits:(CGSize)size { return size; } @end // then use it in your VC @implementation MyViewController - (void)viewDidLoad { [super viewDidLoad]; self.navigationItem.titleView = [[SearchBarWrapper alloc] initWithSearchBar:self.searchController.searchBar]; } @end 

现在还有一个案子还没有解决。 要重现,请执行以下操作:
– 开始肖像
– 激活search字段
– 旋转到风景
– 错误:栏不resize

就我而言,更大的UINavigationBar的高度对我来说不是问题。 我只需要重新排列左右栏button项目。 这是我提出的解决scheme:

 - (void)iOS11FixNavigationItemsVerticalAlignment { [self.navigationController.navigationBar layoutIfNeeded]; NSString * currSysVer = [[UIDevice currentDevice] systemVersion]; if ([currSysVer compare:@"11" options:NSNumericSearch] != NSOrderedAscending) { UIView * navigationBarContentView; for (UIView * subview in [self.navigationController.navigationBar subviews]) { if ([subview isKindOfClass:NSClassFromString(@"_UINavigationBarContentView")]) { navigationBarContentView = subview; break; } } if (navigationBarContentView) { for (UIView * subview in [navigationBarContentView subviews]) { if (![subview isKindOfClass:NSClassFromString(@"_UIButtonBarStackView")]) continue; NSLayoutConstraint * topSpaceConstraint; NSLayoutConstraint * bottomSpaceConstraint; CGFloat topConstraintMultiplier = 1.0f; CGFloat bottomConstraintMultiplier = 1.0f; for (NSLayoutConstraint * constraint in navigationBarContentView.constraints) { if (constraint.firstItem == subview && constraint.firstAttribute == NSLayoutAttributeTop) { topSpaceConstraint = constraint; break; } if (constraint.secondItem == subview && constraint.secondAttribute == NSLayoutAttributeTop) { topConstraintMultiplier = -1.0f; topSpaceConstraint = constraint; break; } } for (NSLayoutConstraint * constraint in navigationBarContentView.constraints) { if (constraint.firstItem == subview && constraint.firstAttribute == NSLayoutAttributeBottom) { bottomSpaceConstraint = constraint; break; } if (constraint.secondItem == subview && constraint.secondAttribute == NSLayoutAttributeBottom) { bottomConstraintMultiplier = -1.0f; bottomSpaceConstraint = constraint; break; } } CGFloat contentViewHeight = navigationBarContentView.frame.size.height; CGFloat subviewHeight = subview.frame.size.height; topSpaceConstraint.constant = topConstraintMultiplier * (contentViewHeight - subviewHeight) / 2.0f; bottomSpaceConstraint.constant = bottomConstraintMultiplier * (contentViewHeight - subviewHeight) / 2.0f; } } } } 

基本上,我们search包含栏button项目的栈视图,然后更改它们的顶部和底部约束值。 是的,这是一个肮脏的黑客,并不会推荐使用它,如果你能以任何其他方式解决你的问题。

编辑:@zgjie答案是这个问题的更好的解决scheme: https ://stackoverflow.com/a/46356265/1713123

看来这是因为在iOS 11中,SearchBar的默认高度值更改为56,而之前的iOS版本则为44。

现在,我已经应用此解决方法,将searchBar高度设置回44:

 let barFrame = searchController.searchBar.frame searchController.searchBar.frame = CGRect(x: 0, y: 0, width: barFrame.width, height: 44) 

另一个解决scheme可以在iOS 11的navigationItem上使用新的searchController属性 :

 navigationItem.searchController = searchController 

但是,这种方式达到searchBar下面的导航标题。

我尝试了各种各样的方法,将大小恢复到原来的44,但是search栏的外观和行为总是很奇怪 – 就像是被拉长了很多,y偏移一样。

我在这里find了一个很好的解决scheme(通过一些其他的stackoverflow后): https : //github.com/DreamTravelingLight/searchBarDemo

只需从SearchViewController派生您的视图控制器,并在您的项目中包括SearchViewController和WMSearchbar类。 (iOS11)其他…丑陋的工作,没有任何丑陋的工作。

所有的解决scheme都不适合我,所以在我推视图控制器之前,我做了:

 override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) self.navigationItem.titleView = UIView() } 

回去时要让search栏显示:

 override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) self.navigationItem.titleView = UISearchBar() } 

在viewDidLoad的“ACKNOWLEDGEMENT”视图控制器上试试这个代码

 self.extendedLayoutIncludesOpaqueBars = true 

我不能使用保持navBar在44的解决scheme。所以,我花了一天,但最后,我find了一个解决scheme,不改变酒吧的高度和位于酒吧中间的button。 问题是button被放置在configuration为水平堆栈视图的堆栈视图中,因此不会调整高度更改。

这是在init中完成的:

 UIBarButtonItem *cancelButton; if (@available(iOS 11.0, *)) { // For iOS11 creating custom button to accomadate the change of navbar + search bar being 56 points self.navBarCustomButton = [UIButton buttonWithType:UIButtonTypeCustom]; [self.navBarCustomButton setTitle:@"Cancel"]; [self.navBarCustomButton addTarget:self action:@selector(cancelButtonTapped) forControlEvents:UIControlEventTouchUpInside]; cancelButton = [[UIBarButtonItem alloc] initWithCustomView:self.navBarCustomButton]; } else { cancelButton = [[UIBarButtonItem alloc] initWithTitle:MagicLocalizedString(@"button.cancel", @"Cancel") style:UIBarButtonItemStylePlain target:self action:@selector(cancelButtonTapped)]; } 

在viewWillApear(或视图添加到导航堆栈之后的任何时候)

  if (@available(iOS 11.0, *)) { UIView *buttonsStackView = [navigationController.navigationBar subviewOfClass:[UIStackView class]]; if (buttonsStackView ) { [buttonsStackView.centerYAnchor constraintEqualToAnchor:navigationController.navigationBar.centerYAnchor].active = YES; [self.navBarCustomButton.heightAnchor constraintEqualToAnchor:buttonsStackView.heightAnchor]; } } 

而subviewOfClass是UIView上的一个类别:

 - (__kindof UIView *)subviewOfClass:(Class)targetClass { // base case if ([self isKindOfClass:targetClass]) { return self; } // recursive for (UIView *subview in self.subviews) { UIView *dfsResult = [subview subviewOfClass:targetClass]; if (dfsResult) { return dfsResult; } } return nil; } 

在我的情况下,我必须减lesstextfield的高度36pt – > 28pt。

在这里输入图像说明

所以我试图改变框架的高度,层的高度。 但是这种方式并不奏效。

最后,我find了一个解决scheme,就是面具。 我想,这不是一个好的方法,但它的工作原理。

  let textField = searchBar.value(forKey: "searchField") as? UITextField textField?.font = UIFont.systemFont(ofSize: 14.0, weight: .regular) textField?.textColor = #colorLiteral(red: 0.1960784314, green: 0.1960784314, blue: 0.1960784314, alpha: 1) textField?.textAlignment = .left if #available(iOS 11, *) { let radius: CGFloat = 5.0 let magnifyIconWidth: CGFloat = 16.0 let inset = UIEdgeInsets(top: 4.0, left: 0, bottom: 4.0, right: 0) let path = CGMutablePath() path.addArc(center: CGPoint(x: searchBar.bounds.size.width - radius - inset.right - magnifyIconWidth, y: inset.top + radius), radius: radius, startAngle: .pi * 3.0/2.0, endAngle: .pi*2.0, clockwise: false) // Right top path.addArc(center: CGPoint(x: searchBar.bounds.size.width - radius - inset.right - magnifyIconWidth, y: searchBar.bounds.size.height - radius - inset.bottom), radius: radius, startAngle: 0, endAngle: .pi/2.0, clockwise: false) // Right Bottom path.addArc(center: CGPoint(x: inset.left + radius, y: searchBar.bounds.size.height - radius - inset.bottom), radius: radius, startAngle: .pi/2.0, endAngle: .pi, clockwise: false) // Left Bottom path.addArc(center: CGPoint(x: inset.left + radius, y: inset.top + radius), radius: radius, startAngle: .pi, endAngle: .pi * 3.0/2.0, clockwise: false) // Left top let maskLayer = CAShapeLayer() maskLayer.path = path maskLayer.fillRule = kCAFillRuleEvenOdd textField?.layer.mask = maskLayer } 

如果要更改textField的框架,可以更改插入。

在iOS 11中,我在NavigationBar和SearchBar下面有两行黑线:

  • 当我从ViewController与UISearchBar推ViewControllers 在这里输入图像说明

  • 当我解雇ViewController与UISearchBar与“拖右”解雇“ 在这里输入图像说明

我的解决scheme是:使用UISearchBar将下面的代码添加到我的ViewController中:

 -(void)viewWillDisappear:(BOOL)animated{ [super viewWillDisappear:animated]; [self.navigationController.view layoutSubviews]; // <<== this fixes the height of the navigation bar } 
 // // Created by Sang Nguyen on 10/23/17. // Copyright © 2017 Sang. All rights reserved. // import Foundation import UIKit class CustomSearchBarView: UISearchBar { final let SearchBarHeight: CGFloat = 44 final let SearchBarPaddingTop: CGFloat = 8 override open func awakeFromNib() { super.awakeFromNib() self.setupUI() } override init(frame: CGRect) { super.init(frame: frame) self.setupUI() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) // fatalError("init(coder:) has not been implemented") } func findTextfield()-> UITextField?{ for view in self.subviews { if view is UITextField { return view as? UITextField } else { for textfield in view.subviews { if textfield is UITextField { return textfield as? UITextField } } } } return nil; } func setupUI(){ if #available(iOS 11.0, *) { self.translatesAutoresizingMaskIntoConstraints = false self.heightAnchor.constraint(equalToConstant: SearchBarHeight).isActive = true } } override func layoutSubviews() { super.layoutSubviews() if #available(iOS 11.0, *) { if let textfield = self.findTextfield() { textfield.frame = CGRect(x: textfield.frame.origin.x, y: SearchBarPaddingTop, width: textfield.frame.width, height: SearchBarHeight - SearchBarPaddingTop * 2)`enter code here` return } } } }