Adding UISearchBar to UITableView - ios

Background: I have a UIViewController which has a UITableView added programmatically. At the top of the UITableView I have a tablHeaderView in which I have placed a UIView. This UIView has a UISearchBar and a segmentedControl. The idea being: that a user can sort the UITableView by some basic categories such as 'Date/Time' or 'Location' etc. They can also search by an item in the programme.
Problem: When I tap the search bar it resizes (which I don't want) and then when I cancel the search it resizes again and stays there until the UIViewController is exited and loaded again.
Code:
-(void)loadTableView
{
usableSpace = [[UIScreen mainScreen] applicationFrame];
usableWidth = usableSpace.size.width;
usableHeight = usableSpace.size.height;
_tableView = [[UITableView alloc] init];
[_tableView setFrame:CGRectMake(0,0,usableWidth, usableHeight)];
[_tableView setDataSource:self];
[_tableView setDelegate:self];
[self.view addSubview:_tableView];
_searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, usableWidth, 44)];
_searchBar.showsCancelButton = YES;
NSLog(#"searchBar height = %fl", _searchBar.frame.size.height);
segmentedControl = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:#"Date/Time", #"Location", #"Speaker", nil]];
segmentedControl.frame = CGRectMake(0, (_searchBar.frame.size.height), usableWidth, (usableHeight * 0.075));
[segmentedControl addTarget:self action:#selector(sortList) forControlEvents:UIControlEventValueChanged];
searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:_searchBar contentsController:self];
searchDisplayController.delegate = self;
searchDisplayController.searchResultsDataSource = self;
searchDisplayController.searchResultsDelegate = self;
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, usableWidth, (usableHeight * 0.15))];
[headerView addSubview:_searchBar];
[headerView addSubview:segmentedControl];
_tableView.tableHeaderView = headerView;
[self.view addSubview:_tableView];
self.tableView = _tableView;
}
What I have tried: I have tried setting the size of the SearchBar, not setting its size. Not having it in a UIView in the tableHeaderView, instead just having it there on its own.
Why does it resize at all and how can I get it to stop?
EDIT: I have just tried the following: In storyboard (where the UIViewController was originally created) I have selected the UIVC in question and in attributes inspector I deselected 'Under Top Bars' and 'Under Bottom Bars' and this appears to have fixed the first part of the animation problem. Now, when I tap in the search bar, the search becomes active but the searchBar does NOT resize. However, when I cancel the searchBar the searchBar still animates and resizes as per the last image in my screenshot. What could be causing THAT resizing?

i've been banging my head on this for too freakin long... props to this dude here for the clues.
if you want your UISearchBar to be in the header along with other views and to scroll with the header instead of sticking at the top, then you've got to remove it and re-add it after the search completes. to be clear, build your header like you already do and then throw this in there as well to handle the screwy animations.
-(void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller {
[self.mySearchBar removeFromSuperview];
self.mySearchBar.frame = CGRectMake(0, 0, 320, 44);
[self.table.tableHeaderView addSubview:self.mySearchBar];
}
As Timothy Moose notes here, "It seems that UISearchDisplayController makes an undocumented assumption that the search bar is the only content of the header view"
...yay apple.

Ok, after hours of reading up and trying different things I think I have found out how to have a UISearchBar where I want it and it seems to work ok. I believe the problem was to do with either having multiple views in the tableHeaderView OR the UISearchBar did not like being with another view inside a 'containing' view.
Here is the code I ended up with that allowed me to have a segmentedControl at the top of my UITableView AND a UISearchBar which actually sat at the top of my UIView (to which the UITableView was added).
-(void)loadTableView
{
usableSpace = [[UIScreen mainScreen] applicationFrame];
usableWidth = usableSpace.size.width;
usableHeight = usableSpace.size.height;
_tableView = [[UITableView alloc] init];
[_tableView setFrame:CGRectMake(0,0,usableWidth, usableHeight)];
[_tableView setDataSource:self];
[_tableView setDelegate:self];
[self.view addSubview:_tableView];
_searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, usableWidth, 44)];
[_searchBar setShowsCancelButton:YES];
NSLog(#"searchBar height = %fl", _searchBar.frame.size.height);
segmentedControl = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:#"Title", #"Date/Time", #"Speaker", nil]];
segmentedControl.frame = CGRectMake(0, (_searchBar.frame.size.height), usableWidth, (usableHeight * 0.075));
segmentedControl.selectedSegmentIndex = 0;
[segmentedControl addTarget:self action:#selector(sortList) forControlEvents:UIControlEventValueChanged];
searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:_searchBar contentsController:self];
searchDisplayController.delegate = self;
searchDisplayController.searchResultsDataSource = self;
searchDisplayController.searchResultsDelegate = self;
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, usableWidth, (usableHeight * 0.15))];
[headerView addSubview:segmentedControl];
_tableView.tableHeaderView = headerView;
[self.view addSubview:_tableView];
[self.view addSubview:_searchBar];
self.tableView = _tableView;
}
This meant that I had:
UIViewController with a UINavigationController, UISearchBar, UITableView. The UITableView had a segmentedConrol. The UISearchBar sits just under the UINavigationController and is always present. The UISearchBar sits at the top of the UITableViewController and scrolls with the UITableViewCells.
If anyone knows why the UISearchBar acted as it did in the question then I would be grateful if they could leave a comment. I know that this problem (or very similar) has been experienced by MANY people and I haven't found a definitive answer anywhere.

Related

How to dismiss a UISearchBar programmatically?

I'm using a UISearchController and a UITableView. When a cell in the UITableView is selected, I'm adding a black UIView above the whole screen with some subviews on it. It works just fine when the UISearchController is inactive. But when it's active, the UISearchBar shows above my black view.
self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.searchController.searchResultsUpdater = self;
self.searchController.dimsBackgroundDuringPresentation = NO;
self.searchController.searchBar.scopeButtonTitles = [NSArray array];
self.searchController.searchBar.delegate = self;
self.searchController.hidesNavigationBarDuringPresentation = NO;
self.searchController.searchBar.backgroundImage = [self imageWithColor:[MySingleton shared].barTintColor];
[self.searchController.searchBar sizeToFit];
[self.view addSubview:self.searchController.searchBar];
myView = [[UIView alloc] initWithFrame:CGRectMake(0, -64, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)];
myView.backgroundColor = [UIColor blackColor];
myView.layer.opacity = 0.9;
[self.view addSubview:myView];
I've tried make it inactive before placing the view,
self.searchController.active = NO;
and add myView to a navigation controller's view
[self.navigationController.view addSubview:myView];
and still no luck. Any idea?
There is a method that will allow you to insert a view above another view in the view hierarchy called: - insertSubview:aboveSubview:. Here's how you could use it:
if (self.searchController.searchBar)
[self.view insertSubview:myView aboveSubview:self.searchController.searchBar];
else
[self.view addSubview:myView];
Try this
[self.searchController setActive:NO];
This is a property of SearchController as per Apple documentation, should do the trick

Adding UISegmentedControl in UISearchDisplayController

I want to add the UISegmentedControl below the searchBar and above the TableView of UISearchDisplayController. Currently UISearchDisplayController only shows its tableView under its SearchBar.
But i want to add a UISegmentedControl below the SearchBar so that I have SearchBar on the top, after SearchBar I have a UISegmentedControl and below that UISegmentedControl I have UITableView. Is that any way to do this using UISearchDisplayController or i have to make my own SearchDisplayController that have its own SearchBar , UISegmentedControl and TableView?
any suggestion? Thanks
Enable ShowScopeBar and add as many as segments by adding scop titles and handle them by following method
By Code
UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
[searchBar setShowsScopeBar:YES];
[searchBar setScopeButtonTitles:#[#"button1",#"button2"]];
[[self view] addSubview:searchBar];
By XIB
Delegate method to handle scope button action
- (void)searchBar:(UISearchBar *)searchBar selectedScopeButtonIndexDidChange:(NSInteger)selectedScope{
}
Create a view in table
UIView *viewsearch=[[UIView alloc]initWithFrame:CGRectMake(0,-10, 320,83)];
[self.tblname addSubview:viewsearch];
[self.view addGestureRecognizer:revealController.panGestureRecognizer]
UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0,5, 320, 40)];
searchBar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
searchBar.delegate=self;
[searchBar setBarTintColor:[UIColor colorWithRed:(249/255.0) green:(9/255.0) blue:(99/255.0) alpha:1]];
searchBar.tintColor = [UIColor whiteColor];
searchBar.placeholder = #"Search items e.g. jacket";
Addsearchbar view in that view.
[viewsearch addSubview:searchBar];
searchBar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
Use UISegmentedControl in this searchview.
NSArray *itemArray = [NSArray arrayWithObjects: #"General", #"Near me", nil];
UISegmentedControl *segmentedControl = [[UISegmentedControl alloc] initWithItems:itemArray];
segmentedControl.frame = CGRectMake(50,53, 225, 22);
segmentedControl.segmentedControlStyle = UISegmentedControlStylePlain;
[segmentedControl addTarget:self action:#selector(MySegmentControlAction:) forControlEvents: UIControlEventValueChanged];
segmentedControl.selectedSegmentIndex = 0;
segmentedControl.tintColor = [UIColor colorWithRed:(249/255.0) green:(10/255.0) blue:(99/255.0) alpha:1];
segmentedControl.autoresizingMask = UIViewAutoresizingFlexibleRightMargin |
UIViewAutoresizingFlexibleLeftMargin |
UIViewAutoresizingFlexibleBottomMargin;
[viewsearch addSubview:segmentedControl];
I find the solution for my Problem that i added the UISegmentedControl as a Header of TableView of UISearchDisplayController. In this way it just looked like that i have added a UISegmentedControl Separately under the searchBar of UISearchDisplayController.
Thank You every one who tried to help.

How to add a custom UIView to Navigation Bar in iOS7+ like this

Is there a way to insert any UIView in NavigationBar like the image below?
Is this not working?
UINavigationBar *navBar = [[UINavigationBar alloc] initWithFrame: CGRectMake(0.0f, 20.0f, 320.0f, 32.0f)];
UIView *tempView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 20)];
[[self view] addSubview: tempView];
[[self view] addSubview: navBar];
UINavigationItem *navItem = [[UINavigationItem alloc] initWithTitle: #"Controls"];
[navBar pushNavigationItem:navItem animated:NO];
In the code below, I embed a view into the navbar, where my embedded view draws the background and the new buttons. The code also deals with relaying out the view when the device is rotated.
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
if (view.superview == nil) {
[self.navigationBar addSubview:view];
[self.navigationBar setBackgroundImage:[[UIImage alloc] init] forBarMetrics:UIBarMetricsDefault];
}
CGRect frame = self.navigationBar.frame;
frame.size.height = MY_NAVBAR_HEIGHT;
self.navigationBar.frame = frame;
view.frame = self.navigationBar.bounds;
}
An alternative solution is to use a regular UIView as a NavBar, and by saying that what I mean is you have to set the UIView in navbar place and hide the NavigationController bar in the main VC and show it in the next one read this article Here https://medium.com/me/stats/post/54bc5fc56d6c

Can't Interact With Controls In Table View Header

I've decided to use a table header view in my app to hold a search bar and a UISegmentedControl. Here is the viewDidLoad of the view controller:
- (void)viewDidLoad
{
[super viewDidLoad];
self.searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 65, 320, 44)];
[self.searchBar sizeToFit];
[self.searchBar setUserInteractionEnabled:YES];
[self setSearchController:[[UISearchDisplayController alloc] initWithSearchBar:self.searchBar contentsController:self]];
self.mainSegment = [[UISegmentedControl alloc] initWithItems:#[#"YouTube", #"iTunes"]];
[self.mainSegment setFrame:CGRectMake(8, 109, 305, 29)];
[self.mainSegment setSelectedIndex:0];
[self.mainSegment addTarget:self action:#selector(searchTypeChanged:) forControlEvents:UIControlEventValueChanged];
[self.mainSegment setUserInteractionEnabled:YES];
UIView* headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 65)];
[headerView setBackgroundColor:[UIColor clearColor]];
[headerView addSubview:self.searchBar];
[headerView addSubview:self.mainSegment];
[headerView bringSubviewToFront:self.searchBar];
[headerView bringSubviewToFront:self.mainSegment];
[headerView setUserInteractionEnabled:YES];
self.tableView.tableHeaderView = headerView;
self.tableView.userInteractionEnabled = YES;
}
This produces a good result:
However, I can't interact with the search bar or the segmented control. I tried setting userInteractionEnabled to YES as shown above, but the problem still remains. Any ideas?
The height of your header view is 65 points. You're inserting your searchbar at Y=65 so it's beyond the bounds of the header rect. Move your searchbar to Y=0 and your segmented control below it, and it's going to work just fine.
Have a nice day :)
USe delegate methods to set up the headerview.Create and return your headerview in this method.
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
Dont forget to set up the table header height.
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
and the <UITableviewDatasource> in header file to indicate the class is actually having your datasource methods to that table
A must read doc

Choppy Paging UIScrollView Experience

I'm interested in implementing a paging UIScrollView experience, very similar to the current Twitter app, where there is a main paging UIScrollView (horizontal scrolling) at the top of the view hierarchy, and several other (vertical scrolling) UIScrollViews or UITableViews as the paging UIScrollView's subview.
I was taking reference from this WWDC video where they described how we could add a/several "zooming" scrollViews as a subview of a bigger "paging" scrollView.
In my current setup, I have:
A ViewController in storyboard with hierarchy as follows: View > ScrollView (contentScrollView) > Several subviews (UIImageViews, UIButtons and UILabels).
When that view is being loaded, I call a method setupPagingScrollView method in its viewDidAppear.
- (void)setupPagingScrollView
{
// Setup the PAGING UIScrollView
self.pagingScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 340, self.view.frame.size.height)];
self.pagingScrollView.contentSize = CGSizeMake(680, self.view.frame.size.height);
self.pagingScrollView.pagingEnabled = YES;
self.pagingScrollView.backgroundColor = [UIColor blackColor];
// Remove the CONTENT UIScrollView (from storyboard) from the view.
// Add the CONTENT UIScrollView (from storyboard), as a subview of the newly created PAGING UIScrollView
[self.contentScrollView removeFromSuperview];
[self.pagingScrollView addSubview:self.contentScrollView];
[self.view addSubview:self.pagingScrollView];
// Create the 2nd page, which is a UITableView
self.tableView = ({
UITableView *tableView = [[UITableView alloc] initWithFrame:CGRectMake(340, 0, 320, self.view.frame.size.height) style:UITableViewStylePlain];
tableView.delegate = self;
tableView.dataSource = self;
tableView.backgroundColor = [UIColor whiteColor];
tableView.tableFooterView = [UIView new];
tableView.contentInset = UIEdgeInsetsMake(50, 0, 0, 0);
tableView;
});
[self.pagingScrollView addSubview:self.tableView];
// UINavigationBar for the UITableView in the 2nd page.
self.likesCommentsNavBar = ({
UINavigationBar *navBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(340, 0, 320, 44)];
UINavigationItem *navItem = [[UINavigationItem alloc] init];
UISegmentedControl *segmentedControl = [[UISegmentedControl alloc] initWithItems:#[#"Likes", #"Comments"]];
[segmentedControl addTarget:self action:#selector(toggleLikesCommentsWithSegmentedControl:) forControlEvents:UIControlEventValueChanged];
segmentedControl.selectedSegmentIndex = 0;
navItem.titleView = segmentedControl;
navBar.items = #[navItem];
navBar;
});
[self.pagingScrollView addSubview:self.likesCommentsNavBar];\
}
My intended end result would be something like the twitter application, just that instead of panning between 3 UITableViews, my first view would be a custom view with some images, labels, and buttons, and the 2nd and 3rd page would be UITableViews.
I have created a mockup of my intended result
Currently, I am able to get the result I want but I realize that there is some choppiness in the performance. Am I doing something wrong here by allocating memory to so many views or something?
Many thanks!
Incase the image loading on the main thread is the problem here, here is an easy way to load images on a background thread
UIImageView *imageView = [[UIImageView alloc] init]; // can be your IBOutlet or something instead
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
UIImage *image = [UIImage imageNamed:#"imageName"];
dispatch_sync(dispatch_get_main_queue(), ^{
imageView.image = image; //can add some fade in animation or something here too
});
});

Resources