UISearchBar increases navigation bar height in iOS 11

后端 未结 19 1450
醉酒成梦
醉酒成梦 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 02:59

    I believe in iOS 11 UISearchBar now has the height equals to 56, and UINavigationBar uses autolayout to fit its subviews hence it increases the height. If you still want to have UISearchBar as titleView as in pre-iOS 11, I found out the best way to do it is to embed UISearchBar in a custom view, and set this view's height to 44, and assign it to 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 讨论(0)
  • 2020-11-28 03:01

    I couldn't use the solution of keeping the navBar at 44. So it took me a day but finally, I found a solution that doesn't change the bar height and position the button in the middle of the bar. The issue is that the buttons are placed in a stack view which is configured as Horizontal stack view and therefore doesn't adjust to the height change.

    This is done on 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)];
    }
    

    on viewWillApear (or anytime after the view was added to the navigation stack)

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

    And subviewOfClass is a category on 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;
    }
    
    0 讨论(0)
  • 2020-11-28 03:03

    EDIT: The @zgjie answer is a better solution for this problem: https://stackoverflow.com/a/46356265/1713123

    It seems this happens because in iOS 11 the default height value of SearchBar was changed to 56, instead 44 on previous iOS versions.

    For now, I've applied this workaround, setting searchBar height back to 44:

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

    Another solution could be use the new searchController property on navigationItem in iOS 11:

    navigationItem.searchController = searchController
    

    But this way da searchBar appears below navigation title.

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

    In Objective-C

    if (@available(iOS 11.0, *)) {
            [self.searchBar.heightAnchor constraintLessThanOrEqualToConstant: 44].active = YES;
    }              
    
    0 讨论(0)
  • 2020-11-28 03:06

    I tried various things to get the size back to the original 44, but then the search bar always looks and behaves weird - like being to far stretched, y-offset and alike.

    I found a nice solution here (via some other stackoverflow post): https://github.com/DreamTravelingLight/searchBarDemo

    Just derive your viewcontroller from the SearchViewController and include in your project the SearchViewController and WMSearchbar classes. Worked out of the box for me without any ugly if (iOS11) else... uglyness.

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

    I found Mai Mai's solution to be the only one that's really usable.
    However it's still not perfect:
    When rotating the device, the search bar is not properly resized and remains in the smaller dimension.

    I have found a fix for that. Here is my code in Objective C with the relevant parts annotated:

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

    Now there is still one case left that I haven't figured out yet. To reproduce do the following:
    - start in portrait
    - activate search field
    - rotate to landscape
    - error: the bar doesn't resize

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