When I initiate a search on UISearchBar which is a child off a UITableView, any other view except the UITableView becomes hidden. This issue only happens on iOS 7. And I dont have any specific code which hides the other views.
To come to the solution I first had to figure out the issue.
When text is input into the UISearchBar, it creates a UITableView which sits on top of the parent view.
To show the hidden parent view, the UITableView created must be offset and re sized to fit within a smaller area.
(void)searchDisplayController:(UISearchDisplayController *)controller didShowSearchResultsTableView:(UITableView *)tableView {
// The tableView the search tableView replaces
CGRect f = self.mainTableView.frame;
CGRect s = self.searchDisplayController.searchBar.frame;
CGRect updatedFrame = CGRectMake(f.origin.x,
f.origin.y + s.size.height,
f.size.width,
f.size.height - s.size.height);
tableView.frame = updatedFrame;
}
Try to add this in the viewDidLoad for the popover UIViewController:
if ([self respondsToSelector:#selector(edgesForExtendedLayout)])
self.edgesForExtendedLayout = UIRectEdgeNone;
Related
Just like in the native iOS Mail app, when I push a UITableViewController onto a UINavigationController, I would like to make it so that the UITableView initially appears slightly scrolled downwards, obscuring its headerView beneath the navigation controller's navigation bar.
At the same time, even if the height of all of the cells is smaller than the height of the table view, it should be possible for the user to scroll up and down to explicitly show or hide the header view again.
With that logic, it would appear that there are two considerations to make for this implementation:
1) Ensuring that the minimum content size of the table view is at least the height of the table view's frame + the height of the header view.
2) When the table view is initially presented, the content offset is incremented by the height of the header view.
I've tried manually setting both the contentOffset and contentSize properties of the table view in 'viewWillAppear', however this appears to have no effect (It's possible the table view is getting reloaded after that point). Trying to set them in 'viewDidAppear' will work, but that's too late as it only gets called once the 'push' animation has completed.
While this sort of question has been asked before for previous iOS versions, I was unable to get any of them working in iOS 8. Additionally, they all dealt with changing the offset, but not the contentSize of the table view.
Has anyone gotten this sort of behavior working in iOS 7 and/or 8 before?
Update - (30/1/2015)
Alright. This wasn't sitting well with me last night, so I had another play with it, and I found a MUCH better and cleaner solution.
I discovered that the tableView property of UITableViewController is NOT readonly. So it actually makes more sense to simply manage the contentSize property in a UITableView subclass and then assign that subclass back to the UITableViewController.
#implementation TOCustomTableView
- (void)setContentSize:(CGSize)contentSize
{
CGFloat scrollInset = self.contentInset.top + self.contentInset.bottom;
CGFloat height = (CGRectGetHeight(self.bounds) - scrollInset) + CGRectGetHeight(self.tableHeaderView.frame);
contentSize.height = MAX(height, contentSize.height);
[super setContentSize:contentSize];
}
#end
---
#implementation TOCustomTableViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.tableView = [[TOCustomTableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
}
#end
This way, the table view's minimum contentSize is always explicitly set to be the height of the table view + the headerView size, achieving the desired effect with zero jittering. :)
Original Answer
trick14 pointed me in the right direction. So the correctly functioning code I ended up with.
- (void)resetTableViewInitialOffset
{
CGPoint contentOffset = self.tableView.contentOffset;
contentOffset.y = self.tableView.contentInset.top + CGRectGetHeight(self.headerView.frame);
self.tableView.contentOffset = contentOffset;
}
- (void)resetTableViewContentSize
{
CGSize contentSize = self.tableView.contentSize;
CGFloat scrollInset = self.tableView.contentInset.top + self.tableView.contentInset.bottom;
CGFloat height = (CGRectGetHeight(self.view.bounds) - scrollInset) + CGRectGetHeight(self.headerView.frame);
contentSize.height = MAX(height, contentSize.height);
self.tableView.contentSize = contentSize;
}
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
if (!self.headerBarInitiallyHidden) {
[self resetTableViewContentSize];
[self resetTableViewInitialOffset];
self.headerBarInitiallyHidden = YES;
}
}
I'm also making sure to call 'resetTableViewContentSize' each time I perform a 'reloadData' on the table view as well.
I've attached a UIView from the storyboard to the top of my UITableView and linked it to the code as IBOutlet, and I want it to be fixed to the top of my tableView. I've tried several ways:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
headView.center = CGPointMake(headView.center.x + scrollView.contentOffset.x, headView.center.y + scrollView.center.y);
[scrollView bringSubviewToFront:headView];
}
and
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGRect newFrame = headView.frame;
newFrame.origin.y = 0;
[headView setFrame:newFrame];
}
and some other ways I found in the site, but none worked for me, I affraid because I connected headView from the storyboard.
How can I do it? many thanks!
Sounds like you have a UITableViewController and have added the view to the table views header view, hence it scrolls with the table.
If this is the case try changing your main view controller to a UIViewController and add the view and tableview there.
I'm encountering this weird bug regarding UISearchDisplayController's table view, which occurs only in iOS 6. I just created my tableview in a nib file and then programmatically added a search bar above it and a search display controller to filter data in the table view:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.mpSearchBar = [[MPSearchBar alloc] initWithFrame:CGRectMake(0, 0, 250, 44)];
self.mpSearchBar.placeholder =#"Card Search";
self.searchController = [[UISearchDisplayController alloc] initWithSearchBar:self.mpSearchBar contentsController:self];
self.searchController.delegate = self;
self.searchController.searchResultsDataSource = self;
self.searchController.searchResultsDelegate = self;
self.resultTableView.delegate = self;
self.resultTableView.dataSource = self;
[self.resultTableView reloadData];
}
When I first enter some query in the search bar, the search display controller filters the data and the controller's result table view works fine. However when I tap the clear button in the search bar and type something else, the result table view which contains the new set of filtered data can no long scrollable. What's weird is, when I try to log the frame and contentSize of the table view, the content size height is larger than the frame height, as it's supposed to be:
- (void)searchDisplayController:(UISearchDisplayController *)controller willShowSearchResultsTableView:(UITableView *)tableView {
tableView.scrollIndicatorInsets = UIEdgeInsetsZero;
tableView.contentInset = UIEdgeInsetsZero;
[tableView hideEmptySeparators];
if (IOS_EQUAL_OR_NEWER_THAN_7){
tableView.separatorInset = UIEdgeInsetsZero;
}
NSLog(#"Frame height %f, Content height %f", tableView.frameHeight, tableView.contentSize.height);
}
And this is what I get from the log:
Frame height 504.000000, Content height 1402.000000
This happens only when I test on iOS 6 devices and I have no clue how to debug this issue.
Please suggest and thanks.
Turns out this is a (not well) known issue of UISearchController's table view in iOS 6. My temporary solution is to get the contentSize from willShowSearchResultsTableView and programmatically set it to the table view in viewDidLayoutSubviews:
- (void) viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
if ([self.searchController isActive]){
// fix wrong content size due to search bar glitch in iOS 6
self.searchController.searchResultsTableView.contentSize = newContentSize;
}
}
Hope this helps anyone who encounters the same problem as mine.
I have a UICollectionView that contains a grid of objects. Above it, in a UICollectionView sectionHeader I have a UISearchBar. I want the search bar to be hidden when the view loads. I try to do it with the following code:
- (void)viewDidLoad
{
[super viewDidLoad];
// 44 = height of search bar.
[self.collectionView setContentOffset:CGPointMake(0, 44) animated:YES];
}
This works when the collectionView contains many objects, when the scrollView have scrollIndicators. But when I e.g. only have one item this doesn't work, the searchBar is always visible. I wonder which approach is the best for achieving my goal, display the UISearchBar when the user scrolls down?
Any suggestions?
If you want to display UISearchBar even user scrolling down down then you can do this by:
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
UISearchBar *tempSearchBar = searchDisplayController.preSetSearchBar;
CGRect rect = tempSearchBar.frame;
rect.origin.y = MIN(0, scrollView.contentOffset.y);
tempsearchBar.frame = rect;
}
And if you want to hide it then you only need to use:
[scrollView alwaysBounceVertical:YES]; // allows always bounce to vertical
It is the default behave if UIScrollbar So by setting value it pretends to collection view that it has some more height then view.
From reference:
If this property is set to YES and bounces is YES, vertical dragging
is allowed even if the content is smaller than the bounds of the
scroll view. The default value is NO.
I think you have this problem because of your content collectionView size. Try to increase it before you set contentOffset:
- (void)viewDidLoad
{
[super viewDidLoad];
self.collectionView.contentSize = CGSizeMake(self.view.frame.size.width, self.view.frame.size.height);
[self.collectionView setContentOffset:CGPointMake(0, 44) animated:YES];
}
You can hide your header view by setting it's size to zero
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section
{
if (headerIsActive == NO)
return CGSizeMake(0, 0);
else
return CGSizeMake(768, 44);
}
I want to get the behavior like this:
I have a UISearchBar, which is a table header view of my tableview. When scrolling the table, the search bar does indeed move, but if you scroll above the boundaries of the table, the search bar never stops touching the navigation bar.
I found a good answer here - Locking a UISearchBar to the top of a UITableView like Game Center
But it not works on iOS 6 - manipulations with table view header frame don't work
What can be the reason of this?
I found a solution, which works on iOS 6 and lower
Make a subclass of UITableView and override layoutSubviews method
- (void)layoutSubviews
{
[super layoutSubviews];
CGRect rect = self.tableHeaderView.frame;
rect.origin.y = MIN(0, self.contentOffset.y);
self.tableHeaderView.frame = rect;
}
If you use the following:
[_tableView setTableHeaderView:_searchBar];
When you scroll the table view beyond the first row, the search bar should also disappear rather than sticking to the top of the view.
Without seeing your code, I can only assume that perhaps you have added the UISearchBar as your section header rather than the table header?
That because iOS6 sdk not update when scrolling, maybe same optimize. so need to call tableview layoutSubviews when scroll.
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
UISearchBar *searchBar = searchDisplayController.searchBar;
CGRect rect = searchBar.frame;
rect.origin.y = MIN(0, scrollView.contentOffset.y);
[scrollView layoutSubviews];
searchBar.frame = rect;
}