首页 文章

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

提问于
浏览
66

我的 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

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

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

17 回答

  • 1

    您可以将高度为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;
        }
    
  • 0

    我相信在iOS 11中,UISearchBar现在的高度等于56,而UINavigationBar使用autolayout来适应其子视图,因此它增加了高度 . 如果您仍然希望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  
        }  
    }
    
  • 0

    在两种情况下,我在iOS5的NavigationBar下使用SearchBar获得黑线:

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

    • 当我用"drag right to dismiss"
      enter image description here
      解雇带有UISearchBar的ViewController时

    我的解决方案是:使用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 Update

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

    在viewDidLoad中的“ACKNOWLEDGMENTS”视图控制器上尝试此代码

    self.extendedLayoutIncludesOpaqueBars = true
    
  • 60

    In Objective-C

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

    我无法使用将navBar保持在44的解决方案 . 所以我花了一天时间,但最后,我找到了一个解决方案,它不会改变条形高度并将按钮放在条形图中间 . 问题是按钮放置在堆栈视图中,该视图配置为水平堆栈视图,因此不会调整高度更改 .

    这是在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;
    }
    
  • -1

    谢谢你们!我终于找到了解决方案 .

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

    • 第一步: viewDidLoad
    -(void)viewDidLoad
    {
        [super viewDidLoad];
        self.extendedLayoutIncludesOpaqueBars = YES;
        ...
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.extendedLayoutIncludesOpaqueBars = true
    }
    
    • 第二步: 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
        }
    
  • 1

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

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

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

  • 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出现在导航 Headers 下方 .

  • 29

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

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

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

  • 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()
    }
    
  • 4

    我发现Mai Mai 's solution to be the only one that'真的很实用 .
    然而,它仍然不完美:
    旋转设备时,搜索栏未正确调整大小并保持较小的尺寸 .

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

    现在还有一个案例,我还没想到 . 重现做以下:

    • 从肖像开始
    • 激活搜索字段
    • 旋转到风景
    • 错误:栏没有调整大小
  • 30

    嗨,使用 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的屏幕,我在_1580463中有这个 .

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

    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
    }()
    

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

  • -2

    在我的情况下,我必须减少textField的高度36pt - > 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的框架,可以更改insets .

  • 11

    我通过在嵌入搜索栏的 Map 视图控制器上添加约束到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
        }
    }
    
  • -1

    您所要做的就是子类化UISearchBar并覆盖“intrinsicContentSize”:

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

    enter image description here

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

相关问题