3

I have a container view that is nearly the full screen sans the status bar.

I then created a UISearchController and a UITableView. I am using ios 9 and doing things programmatically. The bug I am having is when the search bar is touched, the scope options open beneath it but the tableview doesn't slide down correctly. How do I fix this?

The code in my viewDidLoad is:

// Search controller
self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.searchController.searchResultsUpdater = self;
self.searchController.dimsBackgroundDuringPresentation = NO;
self.searchController.searchBar.scopeButtonTitles = @[@"A", @"B", @"C"];
self.searchController.searchBar.delegate = self;
[self.searchController.searchBar setTranslatesAutoresizingMaskIntoConstraints:NO];

// UITableView
self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
self.tableView.translatesAutoresizingMaskIntoConstraints = NO;

// Container view is defined as the whole screen except 20 points at the top where the status bar is
[containerView addSubview:self.searchController.searchBar];
[containerView addSubview:self.tableView];

// The constraints - something is probably wrong here?

// Search bar constraints
NSDictionary *views2 = @{@"searchBar": self.searchController.searchBar};
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[searchBar]|" options:0 metrics:nil views:views2]];
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[searchBar]|" options:0 metrics:nil views:views2]];

// Tableview constraints
NSDictionary *views = @{@"tableView": self.tableView};
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[tableView]|" options:0 metrics:nil views:views]];
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[tableView]|" options:0 metrics:nil views:views]];

I need to make the search bar scope options and table view slide properly together. How is this done programmatically?

cdub
  • 24,555
  • 57
  • 174
  • 303
  • The ironic thing is my main bug was found buried in my code where weeks ago I had "accidentally" added a silly offset to table view causing most of my problems (not in code above) – cdub Dec 02 '15 at 07:00

3 Answers3

1

You can add not only the top layout guide constraint from Interface Builder (Storyboard/xib) but also by programmatically.

Have you ever try KVConstraintExtensionsMaster library to apply constraints that I have implemented. using this library you can add the top and bottom layout guide constraints Programmatically and many more that are not possible or very difficult from storyboard or xib.

Put the below code in the viewDidLoad is:

    // create containerView
    containerView = [UIView prepareNewViewForAutoLayout];
    [containerView setBackgroundColor:[UIColor brownColor]];
    [self.view addSubview:containerView];

    // create Search controller
    self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
    self.searchController.searchResultsUpdater = self;
    self.searchController.dimsBackgroundDuringPresentation = NO;
    self.searchController.searchBar.delegate = self;
    self.searchController.searchBar.scopeButtonTitles = @[@"A", @"B", @"C"];

    // create UITableView
    self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
    [_tableView setBackgroundColor:[UIColor blueColor]];

    [self.tableView prepareViewForAutoLayout];

    [containerView addSubview:self.searchController.searchBar];
    [containerView addSubview:self.tableView];

    // now applying the constraints by using KVConstraintExtensionsMaster library
    // adding leading and trailing contraints of containerView
    [containerView applyLeadingAndTrailingPinConstraintToSuperviewWithPadding:defualtConstant];

    // adding Top and Bottom Layout Guidecontraint of containerView
    [self applyTopLayoutGuideConastrainToView:containerView withPadding:defualtConstant];
    [self applyBottomLayoutGuideConastrainToView:containerView withPadding:defualtConstant];

    // adding Top constraint of searchBar
    [self.searchController.searchBar applyTopPinConstraintToSuperviewWithPadding:defualtConstant];

    // adding leading and trailing contraints of searchBar
    [self.searchController.searchBar applyLeadingAndTrailingPinConstraintToSuperviewWithPadding:defualtConstant];

    // adding leading and trailing contraints of tableView
    [self.tableView applyLeadingAndTrailingPinConstraintToSuperviewWithPadding:defualtConstant];

    // adding Bottom constraint of tableView
    [self.tableView applyBottomPinConstraintToSuperviewWithPadding:defualtConstant];

    // adding vertical constraint between two Sibling views
    // to increase the vertical space between searchBar & tableView, update the spacing value like 10.0 or what you want  
    [self.searchController.searchBar applyConstraintFromSiblingViewAttribute:NSLayoutAttributeBottom toAttribute:NSLayoutAttributeTop ofView:self.tableView spacing:defualtConstant];
keshav vishwkarma
  • 1,832
  • 13
  • 20
  • 1
    *Conceptual question:* why code in the dark when you have a graphical tool which does all the hard work for you, all with potentially 0 bug? – SwiftArchitect Dec 19 '15 at 01:41
  • I wrote the code in between the backtick ( ` ) for eg - ` here code ` you can also use sort key Command + k. – keshav vishwkarma Dec 20 '15 at 19:48
  • @SwiftArchitect Could you please tell me for which graphical tool are you talking about & how can I use it ? – keshav vishwkarma Dec 20 '15 at 19:49
  • 1
    Clarification : there is nothimg wrong with your code and you presented it in a clear, concise manner. I find that *not coding* is an even better approach, and **Interface Builder** *Preview* editor allows you to visualize your layout for all devices in all orientations without coding, building or running a single line of code. Simpler, if not easier. – SwiftArchitect Dec 21 '15 at 02:18
0

Well the constraints are definitely wrong

They should be like this:

NSDictionary *views = @{@"tableView": self.tableView,@"searchBar": self.searchController.searchBar};

[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[searchBar]|" options:0 metrics:nil views:views]];
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[tableView]|" options:0 metrics:nil views:views]];
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[searchBar(44)][tableView]|" options:0 metrics:nil views:views]];

First of all, as you see, you don't need to create a separate dictionary with the views, but you can use one (more simple IMHO)

Second the constraints are as follows:

  1. @"H:|[searchBar]|" --> The searchbar is pinned to the left & right of the containerView with the system default (8px) margin
  2. @"H:|[tableView]|" --> The tableView is pinned to the left & right of the containerView with the system default (8px) margin
  3. @"V:|[searchBar(44)][tableView]|" -->

    • The searchbar is pinned to the top of the containerView with the default margin and has a fixed height of 44 pixels
    • The tableView top is pinned to the bottom of the searchBar without any margin
    • The bottom of the tableView is pinned to the bottom of the containerView
Lefteris
  • 14,550
  • 2
  • 56
  • 95
  • But what happens when the scope options appear? Search bar goes to 88 points but the table view is under the scope options. – cdub Nov 24 '15 at 18:13
  • True but what happens when the seach bar at 44 points goes to a search bar and scope bar at 88 points? – cdub Nov 24 '15 at 18:33
  • Did you try without the fixed brought on the search bar? – Lefteris Nov 24 '15 at 22:28
  • You mean like this: @"V:|[searchBar][tableView]|" instead of this: @"V:|[searchBar(44)][tableView]|"? then yes – cdub Nov 24 '15 at 22:32
  • No. The scope bar still ends up appearing over the top tableview cell. I am on ios 9.0 – cdub Nov 24 '15 at 23:03
  • I think somehow the 88 points of the scope bar never gets sent to the table view. The table view always stays at the 44 point mark. – cdub Nov 24 '15 at 23:46
  • Actually the first part sets it correctly but when I click on search bar to display scope bar options, the screen is all messed up. – cdub Nov 26 '15 at 08:19
  • @chris You could try updating the layout when you show/hide the scope bar by calling `[self.view layoutIfNeeded];` – Lefteris Nov 26 '15 at 13:42
-2

You want to attach the top of the UITableView to the bottom of the top layout guide.

That top layout guide is only available to you when using a Storyboard.

One more reason to use Interface Builder.


Reason number 1 = you wouldn't have this bug in the first place, you would be able to visualize your constraints, and you could achieve all this with exactly 0 lines of code.

I'm absolutely certain that with the right amount of effort, and support from the SO Community, you can do everything in code. I just find that IB saves not only design time, but offloads debugging to the OS, and ensures longer lifespan to any app. Storyboard allows you to concentrate on what makes your app different from my app, instead of agonizing over layout glitches.

SwiftArchitect
  • 47,376
  • 28
  • 140
  • 179
  • Yes I do now that. I wanted to learn the underlying code though. – cdub Nov 24 '15 at 22:40
  • While I understand exactly what you mean, be not fooled in thinking you are getting into better habits this way. In my humble opinion, you will learn exactly as much by using the tools Apple released years ago. 0 line of code will raise your productivity, code quality, and over speed of your application. – SwiftArchitect Nov 24 '15 at 23:27
  • Yes I hear you. So is there no way to do what I want without the Interface Builder? – cdub Nov 24 '15 at 23:46
  • How do I add the UISearchController in storyboard? in IB I only see Search Bar and SearchDisplayController. – cdub Nov 26 '15 at 08:27
  • Here is an excellent tutorial: http://useyourloaf.com/blog/updating-to-the-ios-8-search-controller.html – SwiftArchitect Nov 26 '15 at 08:34
  • Yep that's the tutorial I used. Got it working. As in my comment, had some bad code buried deep in the controller. – cdub Dec 03 '15 at 08:00
  • 1
    @SwiftArchitect, You can add the top layout guide constraint not only from Interface Builder (Storyboard/xib) but also by programmatically. See the blow my answer using KVConstraintExtensionsMaster library to add the top and bottom layout guide constraint programmatically. – keshav vishwkarma Dec 05 '15 at 19:14