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

时间:2017-09-20 09:18:07

标签: ios swift uinavigationbar ios11

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

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

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

enter image description here

现在iOS 11我有:

enter image description here

正如你所看到的,两个搜索栏的舍入有所不同,这并不困扰我。问题是搜索栏会增加导航栏的高度。所以,当我去另一个控制器时,它看起来很奇怪:

enter image description here

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

如何摆脱黑线并在所有视图控制器上保持一致的导航栏高度?

18 个答案:

答案 0 :(得分:64)

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

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

答案 1 :(得分:46)

在两个案例中,我在iOS5的NavigationBar下使用SearchBar获得黑线:

  • 当我使用UISearchBar从ViewController推送另一个ViewControllers时 enter image description here

  • 当我用UISearchBar解雇ViewController时“向右拖动以解除” enter image description here

我的解决方案是:使用UISearchBar将此代码添加到我的ViewController:

-(void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    [self.navigationController.view setNeedsLayout]; // force update layout
    [self.navigationController.view layoutIfNeeded]; // to fix height of the navigation bar
}

Swift 4更新

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    navigationController?.view.setNeedsLayout() // force update layout
    navigationController?.view.layoutIfNeeded() // to fix height of the navigation bar
}

答案 2 :(得分:33)

我相信在iOS 11中,UISearchBar现在的高度等于56,而UINavigationBar使用自动布局来适应其子视图,因此它增加了高度。如果您仍然希望将UISearchBar设置为与iOS 11之前的titleView,我发现最好的方法是将UISearchBar嵌入到自定义视图中,并将此视图的高度设置为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  
    }  
} 

答案 3 :(得分:13)

在" ACKNOWLEDGMENTS"上尝试此代码查看控制器 在viewDidLoad

self.extendedLayoutIncludesOpaqueBars = true

答案 4 :(得分:4)

在Objective-C

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

答案 5 :(得分:1)

谢谢大家!我终于找到了解决方案。

使用UISearchBar将以下代码添加到ViewController。

  1. 第一步:viewDidLoad
-(void)viewDidLoad
{
    [super viewDidLoad];
    self.extendedLayoutIncludesOpaqueBars = YES;
    ...
}
override func viewDidLoad() {
    super.viewDidLoad()
    self.extendedLayoutIncludesOpaqueBars = true
}
  1. 第二步:viewWillDisappear
-(void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
     // force update layout
    [self.navigationController.view setNeedsLayout]; 
    // to fix height of the navigation bar
    [self.navigationController.view layoutIfNeeded];  
}
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        navigationController?.view.setNeedsLayout() // force update layout
        navigationController?.view.layoutIfNeeded() // to fix height of the navigation bar
    }

答案 6 :(得分:1)

这也发生在我身上,它们都在iOS 12.4上运行良好,并且在以上13个版本中变得很奇怪。 问题出在从实现searchBar的UIViewController跳转后,iOS 13导航栏的高度从88增加到100。

在实现searchBar的UIViewController中尝试一下。

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    navigationController?.view.setNeedsLayout()
    navigationController?.view.layoutIfNeeded()
}

修复后预览:

enter image description here enter image description here

修复前的预览:

enter image description here enter image description here

答案 7 :(得分:0)

//
//  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
            }
        }
    }
}

答案 8 :(得分:0)

所有解决方案对我来说都没有用,所以在我推动视图控制器之前我做了:

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    self.navigationItem.titleView = UIView()
}

回程时使搜索栏出现:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    self.navigationItem.titleView = UISearchBar()
}

答案 9 :(得分:0)

我发现Mai Mai的解决方案是唯一真正可用的解决方案 然而,它仍然不完美:
旋转设备时,搜索栏未正确调整大小并保持较小的尺寸。

我找到了解决方法。这是我在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

现在还有一个案例尚未解决。要重现,请执行以下操作:
- 以肖像开始
- 激活搜索栏
- 旋转到横向
- 错误:栏没有调整大小

答案 10 :(得分:0)

编辑:@zgjie答案是解决此问题的更好方法: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)    

另一种解决方案可能是使用new searchController property on navigationItem in iOS 11

navigationItem.searchController = searchController

但是这种方式da searchBar出现在导航标题下面。

答案 11 :(得分:0)

在我的情况下,更大的UINavigationBar的高度对我来说不是问题。我只需要重新调整左右栏按钮项目。这就是我提出的解决方案:

{{DetailsObtained?.name}}

基本上,我们搜索包含条形按钮项的堆栈视图,然后更改它们的顶部和底部约束值。是的,这是一个肮脏的黑客,如果你能以任何其他方式修复你的问题,不建议使用它。

答案 12 :(得分:0)

我通过在嵌入搜索栏的地图视图控制器上添加约束到viewDidAppear来修复此问题

public override func viewDidAppear(_ animated: Bool) {
    if #available(iOS 11.0, *) {

        resultSearchController?.searchBar.heightAnchor.constraint(equalToConstant: 44).isActive = true
        // searchBar.heightAnchor.constraint(equalToConstant: 44).isActive = true
    }
}

答案 13 :(得分:0)

您所要做的就是继承UISearchBar并覆盖" intrinsicContentSize":

@implementation CJSearchBar
-(CGSize)intrinsicContentSize{
    CGSize s = [super intrinsicContentSize];
    s.height = 44;
    return s;
}
@end

enter image description here

答案 14 :(得分:0)

向使用UISearchController,然后将其UISearchBar附加到navigationItem.titleView的人问好。我每天要花4-5个小时疯狂地解决这个问题。遵循iOS 11+推荐的方法,将searchController放入navigation.searchController不仅适合我的情况。具有此searchController / searchBar的屏幕上有一个backButton,一个自定义按钮。

我已经在iOS 10,iOS 11和12中对此进行了测试。我只需要。我不能不解决这个恶魔就回家。考虑到我的截止日期,这是我今天能做的最完美的事情。

因此,我只想分享我所做的辛勤工作,这取决于您将所有内容放到所需的位置(例如,viewModel中的变量)。在这里:

在我的第一个屏幕(例如,没有此搜索控制器的主屏幕)中,我在viewDidLoad()中拥有它。

self.extendedLayoutIncludesOpaqueBars = true

在第二个屏幕中,它是带有searchController的屏幕,我在viewDidAppear中有它。

覆盖func viewDidAppear(_动画:布尔){         super.viewDidAppear(动画)

    let systemMajorVersion = ProcessInfo.processInfo.operatingSystemVersion.majorVersion
    if systemMajorVersion < 12 {
        // Place the search bar in the navigation item's title view.
        self.navigationItem.titleView = self.searchController.searchBar
    }

    if systemMajorVersion >= 11 {

        self.extendedLayoutIncludesOpaqueBars = true

        UIView.animate(withDuration: 0.3) {
            self.navigationController?.navigationBar.setNeedsLayout()
            self.navigationController?.navigationBar.layoutIfNeeded()
        }

        self.tableView.contentInset = UIEdgeInsets(top: -40, left: 0, bottom: 0, right: 0)

        if self.viewHadAppeared {
            self.tableView.contentInset = .zero
        }
    }

    self.viewHadAppeared = true // this is set to false by default.
}

这是我的searchController的声明:

lazy var searchController: UISearchController = {
    let searchController = UISearchController(searchResultsController: nil)
    searchController.hidesNavigationBarDuringPresentation = false
    searchController.dimsBackgroundDuringPresentation = false
    searchController.searchBar.textField?.backgroundColor = .lalaDarkWhiteColor
    searchController.searchBar.textField?.tintColor = .lalaDarkGray
    searchController.searchBar.backgroundColor = .white
    return searchController
}()

所以我希望有一天能对某人有所帮助。

答案 15 :(得分:0)

无法发表评论,但想分享一些我遇到的其他问题,尽管花费了很多时间,但即使使用了其他解决方案之一,也试图弄清这个问题的深处。

看来对我来说最好的解决方法是Andrew's answer

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    navigationController?.view.setNeedsLayout() // force update layout
    navigationController?.view.layoutIfNeeded() // to fix height of the navigation bar
}

但是,如果您的UINavigationBar,至少在iOS 12.1中是

  • 已将isTranslucent设置为false,带有搜索栏的View Controller似乎无法以交互方式关闭时重新调整视图的布局(通过后退按钮正常关闭似乎起作用)。
  • 使用setBackgroundImage(UIImage(), for: .default)设置了背景图片,过渡动画无法正常工作,完成后将跳回到其位置。

这些特殊属性设置为使导航栏以某种方式显示,因此,我需要进行一些调整以使其恢复原状,或忍受怪异的行为。如果我碰到其他问题或发现其他解决方案或其他OS版本的差异,将尝试记住更新以上内容。

答案 16 :(得分:-1)

我尝试了各种各样的东西来使尺寸恢复到原来的44,但随后搜索栏总是看起来和表现得很奇怪 - 比如远远伸展,y偏移和相似。

我在这里找到了一个不错的解决方案(通过其他一些stackoverflow帖子): https://github.com/DreamTravelingLight/searchBarDemo

只需从SearchViewController派生您的viewcontroller,并在您的项目中包含SearchViewController和WMSearchbar类。开箱即用,没有任何丑陋的if(iOS11)其他......丑陋。

答案 17 :(得分:-1)

就我而言,我必须减少textField的高度36pt - &gt; 28PT。

enter image description here

所以我试着改变框架的高度,图层的高度。但这些方法没有用。

最后,我找到了一个面具的解决方案。 我认为,这不是一个好方法,但它有效。

    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的框架,可以更改插入内容。