searchDisplayControllerWillEndSearch goes out of the UIView when end searching - ios

I've a UIView in which I've placed a UISearchBar and a UIButton below are the screenshots that explains the problem:
^This is how it appears when I first run the app
^This is how it gets when I want to enter the text
^Finally this is the size it gets after I end the searchThe most important point here is that I'm not using UINavigationBar the red is a UIView. I've haven't coded anything for it's UI, I just placed it in the .xib and set it via autoResizing. They only this I wrote for UISearchBar was [_searchBarTop setBackgroundImage:[UIImage new]]; which was just to get the background image vanished.I've tried self.searchBarTop.clipsToBounds = YES; and this
- (void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller
{
self.searchDisplayController.searchBar.translatesAutoresizingMaskIntoConstraints = YES;
[self.searchDisplayController setActive:NO animated:YES];
}
I'm using searchdisplaycontroller and want to use that
But it's still the same. Any suggestions?

If you're using a simple UISearchBar in a UIView, you don't need to use UISearchController per sè. You can simply use UISearchBar and it's respective delegates instead.
As for the resizing issue, I think you have the autoresizing at flexible width, whereas you need static width, with static sides. Apply this to both your UIView and the embedded UISearchBar. That should fix your issue. Let me know if the problem persists.
If autoresizing doesn't work, you can just force it back like this:
-(void)searchBarTextDidEndEditing:(UISearchBar *)searchBar {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.01 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
CGRect frame = self.searchBarTop.frame;
frame.origin.x = 33;
frame.size.width = self.view.frame.size.width - 41;
[UIView animateWithDuration:0.5 animations:^{
self.searchBarTop.frame = frame;
}];
});
}

UISearchDisplayController was first deprecated in iOS 8.0, as indeed was UISearchDisplayDelegate. You should use UISearchController its delegate, UISearchControllerDelegate and its searchBar property instead.
EDIT - Add Example
// your class needs to conform to the following protocols
<UISearchResultsUpdating, UISearchControllerDelegate>
// define property for your search controller
#property (nonatomic) UISearchController *mySearchController;
// instantiate the search controller - in viewDidLoad should work
// if you want to handle results manually the searchResultsController can be nil, or you can set it to
self.mySearchController = [[UISearchController alloc]initWithSearchResultsController:nil];
[self.mySearchController.searchBar sizeToFit];
self.mySearchController.searchResultsUpdater = self;
self.mySearchController.delegate = self;
self.mySearchController.dimsBackgroundDuringPresentation = NO;
// add the searcher to a properly constrained "Container" or "wrapper" UIView
[self.containerView addSubView:self.mySearchController.searchBar];
[self.mySearchController.searchBar sizeToFit];
self.definesPresentationContext = YES;
you can then respond to the input in the search bar by implementing the UISearchResultsUpdating protocol's required method:
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController{
NSString *text = searchController.searchBar.text;
/// do whatever you need to with the text typed in to the search bar
}
And Finally, always read Apple's documentation

Related

iOS Fix search bar on top of the UITableViewController?

I'm adding search bar on table header and floating it in scrollViewDidScroll method, but when i scroll without click on search bar(i.e. i go to the view and do scroll) then search bar doesn't stay on top but it scroll up with table however once i click on search bar and click cancel button on search bar and then if i scroll the table, search bar stays on top.here is my code-
-(void)viewDidLoad {
[super viewDidLoad];
UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
searchBar.delegate = self;
searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self];
searchDisplayController.delegate = self;
searchDisplayController.searchResultsDataSource = self;
searchDisplayController.searchResultsDelegate = self;
UIView *tableHeaderView = [[UIView alloc] initWithFrame:searchDisplayController.searchBar.frame];
[tableHeaderView addSubview:searchDisplayController.searchBar];
[tableView setTableHeaderView:tableHeaderView];
isSearching = NO;
}
-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
UISearchBar *searchBar = searchDisplayController.searchBar;
CGRect searchBarFrame = searchBar.frame;
if (isSearching) {
searchBarFrame.origin.y = 0;
} else {
searchBarFrame.origin.y = MAX(0, scrollView.contentOffset.y + scrollView.contentInset.top);
}
searchDisplayController.searchBar.frame = searchBarFrame;
}
- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller {
isSearching = YES;
}
-(void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller {
isSearching = NO;
}
Note that I'm using UITableViewController sub class and don't want to change it to UIViewController.
Any help would be appreciated.
Edit: I also using section header in this UITableViewController, in other UITableViewController there is no section header and this code working fine.Is this a problem with section header and table header together?
The reason why your searchbar is scrolling with the table contents is that you have put it directly IN the table, thus making it a child header section of the table. and that section ALWAYS scrolls…
Here is how this this can be achieved. And it is actually quite simple. (The following example relies on Storyboard, but the mechanism is the same whatever you are using) :
1) Use a UIVIewController and NOT a UITableViewController
2) Add a UITableView as the child of the parent UIView
3) Add a UISearchBarController also as a child view of the UIView, NOT as a child of the UITableView (UITableView and UISearchController are siblings)
you should have the following layout :
EDIT : The important thing to remember is to put the UISearchBarController ABOVE the sibling UITableView. Otherwise you may see the UITableView overlap the UISearchBarController when the latter is focused.
EDIT 2 : BTW, if you are using AutoLayout, remember to set the TOP constraint of the tableView relative to the SearchBar…
Run it and admire the result.
Hope this helps.
There is not a way to maintain the header of a tableView fixed
1- could use an UIViewController instead of UITableViewController.
2- add subview (UIView) for header.
3- and add another subview for the tableview.

UITableView content overlaps Status Bar when UISearchBar is active

I have a UITableViewController with a UISearchBar and UISearchDisplayController. That exists inside a Container View in a UIViewController which is in a UINavigationController. I made this image to help describe the structure:
This is what it really looks like:
When I tap the Search Bar, I have to hide the Nav Bar. Normally, this would happen on its own, but since my UITableViewController is inside a Container View, I have to handle that change myself. This is what it looks like then, note that the Status Bar is white because the Nav Bar is white, even though it is Hidden at the moment.
Once I start typing in some search text, the results show up. If I scroll those results upward, they pass underneath the Search Bar, but they overlap the Status bar which is very unattractive.
If the Container View isn't involved, then this all works as intended and the table content passes underneath the Status Bar, but with the ContainerView involved, the table text and status bar collide.
How do I get the text to travel under the Status Bar like normal?
I have search this for hours and my final result was to put this line in viewDidLoad:
self.extendedLayoutIncludesOpaqueBars = YES;
Problem solved :)
Try setting the definesPresentationContext in viewDidLoad of your TableViewController
Swift
override func viewDidLoad() {
super.viewDidLoad()
definesPresentationContext = true
}
Objective-C
- (void)viewDidLoad {
[super viewDidLoad];
self.definesPresentationContext = YES;
}
Here's what worked for me:
DO:
Use UISearchController (not a separately placed UISearchBar)
Place your VC in a UINavigationController if it isn't already. Set the nav not to "Show Navigation Bar" if desired.
Use autolayout for the UITableView (not springs and struts) and pin the top of the table to the top of the VC's view.
Add this delegate method:
- (UIBarPosition)positionForBar:(id<UIBarPositioning>)bar {
return UIBarPositionTopAttached;
}
DON'T:
Fiddle with edgesForExtendedLayout
Fiddle with extendedLayoutIncludesOpaqueBars
Fiddle with the table's contentInset
Basically this is due to the traslucency of the nav bar, usually the view controller fix that overlapping, by correcting the top insets of the owned view or subview if they are(or inherits) from UIScrollView. You have 2 options, one is to set the traslucency of the navbar to no, the other is set the edgeForExtendedLayout to none ore leave only bottom.
- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller {
self.navigationController.navigationBar.translucent = YES;
}
- (void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller {
self.navigationController.navigationBar.translucent = NO;
}
These advices works only on iOS7, if you are deploying on lower target check before settings those properties.
Another way around, but I didn't tested could be read the --topLayoutGuide length and in the -searchDisplayControllerWillBeginSearch try to set a topInsets of the same length. In this way you should still preserve the translucency.
I have UISearchBar and UISearchDisplayController.
In viewdidload:
self.edgesForExtendedLayout = UIRectEdgeNone;
[searchDisplayController.searchBar setBackgroundImage:[self imageWithColor:ETSBaseColor] forBarPosition:0 barMetrics:UIBarMetricsDefault];
method that obtain image from UIColor:
- (UIImage *)imageWithColor:(UIColor *)color
{
CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, rect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
I had the same problem:
- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller
{
controller.searchBar.searchBarStyle = UISearchBarStyleDefault; // Used to cover UIStatusBar
}
- (void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller
{
controller.searchBar.searchBarStyle = UISearchBarStyleMinimal; // Used not to show top and bottom separator lines
}
In my case I don't want to hide the UINavigationBar but I had similar problems with gapes and other side effects. One of them was a missing UISearchBar after switching between UIViewControllers while the UISearchDisplayController is visible (I'm using SWRevealViewController to switch between UIViewController). This problem occurs only on iPads. It came out that the UISearchBar suddenly hides behind the UINavigationBar. Now I solved all my Problems with the following lines of code in the UITableViewController which is presented in a UIContainerView:
- (UINavigationController *)navigationController {
return nil;
}
Those lines prevent the UISearchDisplayController to reach and change my UINavigationController. I also subclassed this method into "MyContainerTableViewController" class and use this class now for all embedded UITableViewController.
I'm still using UISearchDisplayController to Support iOS 7.
The following hack worked for me:
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return (self.searchController.isActive && section == 0) ? 22.0f : 0.0f;
}

iOS 7 UISearchBar right spacing

Don't know why, my search bar in iOS 7 is leaving a right space. It's ok in iOS 6.
I know it has something to do with the section index, because if I remove it the space disappears, but I don't know how to fix it. Any thoughts?
Embed your UISearchBar in a UIView and then add that as the tableHeaderView. Structuring it that way in a storyboard worked for me. I'm guessing iOS resizes the UISearchBar in the tableHeaderView, but leaves a basic UIView alone (and doesn't bother to look inside it).
You might also want to make the section index transparent, which I did with:
[[UITableView appearance] setSectionIndexBackgroundColor:[UIColor clearColor]];
[[UITableView appearance] setSectionIndexTrackingBackgroundColor:[UIColor clearColor]];
Until a better answer appears, I just manually changed the frame of the search bar like this:
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
CGRect barFrame = self.searchBar.frame;
barFrame.size.width = self.view.bounds.size.width;
self.searchBar.frame = barFrame;
}
I had this same issue with the iPhone 6/ 6Plus when using a SearchDisplayController. (Using Swift)
I tried setting the frame of the search bar but with no luck but i noticed that if i tapped on the textField of the UISearchBar and then cancelled it then it would take on the proper size of the view. I therefore managed to fix the issue by calling the code below in ViewDidLoad of the viewController using the search.
self.searchController.setActive(true, animated: false)
self.searchController.setActive(false, animated: false)
self.contactsTableView.sectionIndexBackgroundColor = [UIColor clearColor];
The reason for that white edge is because your index layer has a white background and is on top of the search bar. This should be sufficient.
Add the search bar inside a UIView put as tableView's header view. Set the tableview's sectionIndexBackgroundColor to clear color because it covers the header.
Tested with iOS 7, 7.1;
Because the table view always leaves 15px on the right for section Indexes View, so you should resize the Seach bar after reloading the table view
First:
self.tblData.sectionIndexBackgroundColor = [UIColor clearColor]; //(iOS >= 7 only)
Cheating time:
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
[self performSelector:#selector(resizeSearchBar) withObject:nil afterDelay:0.01];
}
- (void) resizeSearchBar
{
CGRect frame = self.searchBar.frame;
if (frame.size.width < self.tblData.frame.size.width) {
frame.size.width = self.tblData.frame.size.width;
}
self.searchBar.frame = frame;
}
- (void) reloadTableData // call it anytime you want to reload table view
{
[self.tblData reloadData];
[self performSelector:#selector(resizeSearchBar) withObject:nil afterDelay:0.01];
}
Suggest
Dont cheat like me, just do the simpler way:
self.searchBar.searchBarStyle = UISearchBarStyleMinimal; // iOS >= 7 only
I also attached a UISearcBar in my application, and nothing is wrong there even my application supports rotation also.
Could you try removing and re creating UISearchBar in storyboard/xib
I added the search bar as a subview of the top-level view instead of the table view. Used autolayout to pin the searchbar to the top guide, and a vertical space constraint of 0 between the search bar and the table view.
The accepted solution with the method viewDidLayoutSubviews makes the screen flicker.
Instead what I did was create a subclass of UISearchBar that simply does this:
FullWidthSearchBar.h:
#interface FullWidthSearchBar : UISearchBar
#end
FullWidthSearchBar.m:
#import "FullWidthSearchBar.h"
#implementation FullWidthSearchBar
- (void)setFrame:(CGRect)frame {
frame.size.width = self.superview.bounds.size.width;
[super setFrame:frame];
}
#end
And then I assigned that class to the search bar on my xib:
The problem is the right white block, so if we change the block color the same as the search bar background, it looks normal.
just
if (IOS7) {
self.tableview.backgroundColor = [UIColor colorWithPatternImage:self.searchBar.backgroundImage];
}

UIRefreshControl hidden / obscured by my UINavigationController's UINavigationBar

I'm attempting to use a UIRefreshControl inside my UITableViewController which itself is inside a UINavigationController, which has its hidesNavigationBar property set to NO (so the navigation bar is visible).
The UIRefreshControl works, but is obscured by the UINavigationBar. I'm surprised I can't find anyone else who has run into this problem.
Possible relevant points:
I set the rootViewController of my UIWindow to be my UINavigationController.
I set the initial view controller of the UINavigationController by setting the viewControllers property of the UINavigationController.
My UITableViewController subclass is instantiated with a nib.
I instantiate my UIRefreshControl in the viewDidLoad method of my UITableViewController subclass. I set the refreshControl property of the UITableViewController subclass in this method.
The UIRefreshControl works perfectly fine, and I can see a portion of it, but it is obscured by my UINavigationBar. It looks completely normal if I set hidesNavigationBar to YES (but I don't want to hide it).
Edit:
The code used to create and position my UIRefreshControl is:
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self
action:#selector(toggleRefresh:)
forControlEvents:UIControlEventValueChanged];
self.refreshControl = refreshControl;
This code snippet is in the viewDidLoad method of my UITableViewController subclass, which is a child view controller of a UINavigationViewController.
For those targeting iOS 7, there seems to be a new issue present where the UIRefreshControl is drawn behind the UITableView's backgroundView. I experienced this both when initializing the UIRefreshControl programatically and from a storyboard. A simple workaround is to update the zPosition of the UIRefreshControl in viewDidLoad of your UITableViewController:
self.refreshControl.layer.zPosition = self.tableView.backgroundView.layer.zPosition + 1;
I've find a real solution, here it is:
I've a UIViewController inside a UINavigationController with a translucent NavigationBar. Inside the UIViewController there is the UITableView.
I want to add a UIRefreshControl but when I do it, it's hidden by the NavigationBar, like you explain.
Here is my code to make it work:
// Add a UITableViewController
self.tblViewController = [[UITableViewController alloc] init];
// Set the UITableView to it
self.tblViewController.tableView = self.tblView;
// Initialize the UIRefreshControl and set it's method
self.refreshControl = [[UIRefreshControl alloc] init];
[self.refreshControl addTarget:self action:#selector(refreshTable) forControlEvents:UIControlEventValueChanged];
// Set the RefreshControl to the UITableViewController
self.tblViewController.refreshControl = self.refreshControl;
// Here is the thing ! Just change the contentInset to push down the UITableView content to 64 pixels (StatusBar + NavigationBar)
self.tblView.contentInset = UIEdgeInsetsMake(64.f, 0.f, 0.f, 0.f);
With this code, your UITableViewController will show the RefreshControl perfectly and keep the translucent NavigationBar effect when you scroll down the cells.
It looks like a bug to me, because it only occures when the contentOffset property of the tableView is 0
see this question
UIRefreshControl not showing spiny when calling beginRefreshing and contentOffset is 0
I fixed that with the following code (method for the UITableViewController) :
- (void)beginRefreshingTableView {
[self.refreshControl beginRefreshing];
if (self.tableView.contentOffset.y == 0) {
[UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^(void){
self.tableView.contentOffset = CGPointMake(0, -self.refreshControl.frame.size.height);
} completion:^(BOOL finished){
}];
}
}
In iOS 7, self.view is under the navigationBar, except that you write something as follows,
self.edgesForExtendedLayout = UIRectEdgeNone; // or UIRectEdgeAll & ~UIRectEdgeTop
or
self.navigationViewController.navigationbar.translucent = NO;
Using #Jonathan's answer I got this working well. But since I am using storyboard I set the content inset there like so: Which in case someones needs:
(xcode 6.4)
Do not call -setTranslucent: on your UINavigationBar. Then, your refresh control will be positioned properly, below the navigation bar.

Why my UISearchBar`s frame is changed by the UISearchDisplayController

I write UISearchBar in my TopBar.m like this:
_tempSearchBar =[[UISearchBar alloc]initWithFrame:CGRectMake(44, 0, 320 - 44, 43)];
_tempSearchBar.barStyle=UIBarStyleDefault;
_tempSearchBar.placeholder=#"搜索";
[self addSubview:_tempSearchBar];
the result is like this, it is right.
and then I write UISearchDisplayController in another class like this:
_topBar.tempSearchBar.delegate = self;
_searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:_topBar.tempSearchBar contentsController:self];
[_searchDisplayController setDelegate:self];
[_searchDisplayController setSearchResultsDataSource:self];
the UISearchBarDelegate is like this:
#pragma mark -
#pragma mark UISearchBarDelegate
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
{
[_searchDisplayController setActive:YES animated:YES];
}
when I click the UISearchBar , it show like this , the searchBar`s frame is changed.why?
when I cancel the UISearchDisplayController it is like this :
why the frame is changed? The width is changed from 320-44 to 320 by the UISearchDisplayController?
thanks.
UISearchDisplayController expands the search bar to the width of its superview. The simplest solution that I have found is to place the search bar inside another UIView that has the width I am looking for.
The searchBar's frame is changed by the UIKit, so I changed the searchBar's frame back myself.
I changed the searchBar's frame in the below delegate.
One is UISearchBar's delegate:
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar {
[searchBar setFrame:CGRectMake(44, 0, 320 - 44, 43)];
}
Another is UISearchDisplayController's delegate:
- (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller{
[controller.searchBar setFrame:CGRectMake(44, 0, 320 - 44, 43)];
[self.searchDisplayController.searchResultsTableView setDelegate:self];
}
It can work and I can get the right frame, but when I click the searchBar it will shake a little.
It is not the best way to do it, but it can work. Does anyone have a better method?
Update:
I have debugged the UISearchBar and UISearchDisplayController for a few hours, but it has a little bug: When I endEditing the searchBar's width will become 320px, and then will become my width. I can not change the cancelButton's background color. So I wrote a custom SearchDisplayController, with a UISearchBar property and a UITableView property. It works well for me.
Call the delegate method
- (void) searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller
{
[controller.searchBar setFrame:CGRectMake(0,31, 320 , 43)];
[self.searchDisplayController.searchResultsTableView setDelegate:self];
}
You can handle the cancel button of searchBar using - (void)setShowsCancelButton:animated:
If you do not want to show cancel button (as cancel button will change the frame of searchBar)
just write this in delegate
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
{
[searchBar setShowsCancelButton:NO animated:YES];
}
Updated:
An only possible solution seems to be finding the cancel button from SearchBar view hierarchy and hiding it.
for (UIView *possibleButton in searchBar.subviews)
{
if ([possibleButton isKindOfClass:[UIButton class]])
{
UIButton *cancelButton = (UIButton*)possibleButton;
cancelButton.hidden = YES;
break;
}
}

Resources