Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIsearchController inside UIViewController using Auto Layout

Has anyone been successful implementing a UIViewController that contais both a UISearchController searchBar and a UItableView while laying everything out using Auto Layout?

I'm trying to achieve something similar to what 1Password does on the iPhone: a fixed searchBar on top of a tableView (not part of its tableHeaderView). When the UISearchController that owns the searchBar gets activated, its searchBar animates to show the scope buttons and thus the tableView moves down a bit.

I have got the basics of this layout working correctly with this class:

//
//  ViewController.m
//  UISearchControllerIssues
//
//  Created by Aloha Silver on 05/02/16.
//  Copyright © 2016 ABC. All rights reserved.
//

#import "ViewController.h"

@interface ViewController () <UISearchResultsUpdating, UITableViewDataSource, UITableViewDelegate>

@property (nonatomic, strong) UISearchController *searchController;

@property (nonatomic, strong) UITableView *tableView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    [self setupTableView];
    [self setupSearchInterface];
    [self setupConstraints];

    self.edgesForExtendedLayout = UIRectEdgeNone;

    self.extendedLayoutIncludesOpaqueBars = YES;
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];

    [self.searchController.searchBar sizeToFit];
}

- (void)setupTableView {
    self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];
    self.tableView.dataSource = self;
    self.tableView.delegate = self;
    self.tableView.translatesAutoresizingMaskIntoConstraints = NO;

    [self.view addSubview:self.tableView];
}

- (void)setupSearchInterface {
    self.definesPresentationContext = YES;

    self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
    self.searchController.dimsBackgroundDuringPresentation = NO;
    self.searchController.hidesNavigationBarDuringPresentation = NO;
    self.searchController.searchBar.scopeButtonTitles = @[@"One", @"Two"];
    self.searchController.searchBar.translatesAutoresizingMaskIntoConstraints = NO;
    self.searchController.searchResultsUpdater = self;

    [self.view addSubview:self.searchController.searchBar];
}

- (void)setupConstraints {
    NSDictionary *layoutViews = @{@"searchBar": self.searchController.searchBar, @"tableView": self.tableView, @"topLayoutGuide": self.topLayoutGuide};

    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[searchBar]|" options:0 metrics:nil views:layoutViews]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[tableView]|" options:0 metrics:nil views:layoutViews]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[searchBar(44)][tableView]|" options:0 metrics:nil views:layoutViews]];
}

- (void)updateSearchResultsForSearchController:(UISearchController *)searchController {
    NSLog(@"Update should happen here");
}

#pragma mark - UITableViewDataSource

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 100;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellID = @"CellID";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellID];

    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellID];
    }

    cell.textLabel.text = [NSString stringWithFormat:@"Cell number %ld", (long)indexPath.row];

    return cell;
}

@end

It is embedded in a UINavigationController instance and initially runs as expect, like the following screenshots show:

Initial Layout Fixed SearchBar

Trouble arises when the searchBar gets activated. It seems to disappear from screen, but after carefully inspecting the view, we determine that it is actually onscreen, but with a width of zero. Here's a picture showing what is presented at this time:

UISearchBar Gone

I'm not that experienced with Auto Layout, so I'm left thinking there must be something wrong with my constraints, although I don't mess with them when activating the UISearchController.

Is there any way of making this work?

like image 888
Aloha Silver Avatar asked Dec 18 '22 20:12

Aloha Silver


1 Answers

The UISearchController moves the search bar around when it's tapped, so it doesn't always play well with your constraints.

Instead of setting your constraints directly on the search bar, add an empty placeholder view that will hold your search bar and then place the search bar in it procedurally in viewDidLoad(). Set your constraints on this placeholder instead. Just match the search bar's frame to the placeholder's bounds and leave translatesAutoresizingMaskIntoConstraints set to true.

Sorry, I'm not sure how this placeholder view will handle the size change with the scope buttons. Hopefully you can figure out how to get that part working with auto layout after the change.

like image 132
Dave Batton Avatar answered Jan 06 '23 03:01

Dave Batton