UISearchBar increases navigation bar height in iOS 11

后端 未结 19 1452
醉酒成梦
醉酒成梦 2020-11-28 02:47

I have my UISearchBar being part of the navigation bar like:

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


        
相关标签:
19条回答
  • 2020-11-28 03:16

    You can add a constraint of height 44 to the search bar for iOS 11.

    // Swift

    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 讨论(0)
  • 2020-11-28 03:16

    In my case, bigger UINavigationBar's height wasn't a problem for me. I just needed to realign left and right bar button items. That's the solution i've come up with:

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

    Basically, we search for stack views that contain bar button items and then changing their's top and bottom constraints values. Yeah, it's a dirt hack, and won't recommend to use it if you can fix your issue in any other way.

    0 讨论(0)
  • 2020-11-28 03:17

    In my case, I have to decrease the textField's height 36pt -> 28pt.

    So I tried to change the frame's height, layer's height. But the ways didn't work.

    Finally, I found a solution that's the mask. I think, It's not a good way but it works.

        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
        }
    

    You can change the insets, if you want to change the textField's frame.

    0 讨论(0)
  • 2020-11-28 03:19
    //
    //  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
                }
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-28 03:21

    This happen to me too, all running well in iOS 12.4 and getting weird in 13 above. The problem is in iOS 13 navigation bar height increase from 88 to 100 after jump from UIViewController that implement searchBar.

    Try this in your UIViewController that implement searchBar.

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

    Preview after fixing:

    Preview before fixing:

    0 讨论(0)
  • 2020-11-28 03:21

    Hi to the people who uses UISearchController and then attaching its UISearchBar to the navigationItem.titleView. I've spend a crazy 4-5 hours of my day to solve this. Following the iOS 11+ recommended approach, which is putting the searchController to the navigation.searchController is not just right for my case. The screen that has this searchController/searchBar has a backButton, a custom one.

    I have tested this in iOS 10, iOS 11, and 12. In different devices. I just had to. I can't go home without solving this demon. This is the most perfect I could do for today, given my tight deadline.

    So I just wanna share this hard work that I did, it's up to you to put everything into where ever you want (ex. variables in your viewModel). Here it goes:

    In my first screen (say home screen, that does not have this search controller), I have this in my viewDidLoad().

    self.extendedLayoutIncludesOpaqueBars = true
    

    In my second screen, the one that has the searchController, I have this in my viewDidAppear.

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

    and here's my searchController's declaration:

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

    So I hope this helps someone someday.

    0 讨论(0)
提交回复
热议问题