UITableView setContentOffset not working - ios

I am trying to get my UITableView to have an "overscroll" search bar. I have followed something pretty similar to this tutorial and it basically works. Unfortunately if the uitableview doesn't have enough content to be scrollable, searchbar cannot be hidden once it is pulled down. Does anyone know how to make a searchbar in a uitableview be hidden by default(which this tutorial does do) and then be able to disappear again when the user "scrolls" down?

try this.
- (void) viewWillAppear:(BOOL)animated{
....
[self hideSearchBar];
}
-(void)hideSearchBar:{
[self.tableView setContentOffset:CGPointMake(0, searchBar.height];
}
if dont work, say something.

Related

how to make a tableview take off where it was after switching back from another view? [duplicate]

I have a bit of a problem with my iOS app in xcode. I have a UITableView that loads a few hundred cells. When I scroll down to a specific cell and drill down to detailedviewcontrollers and return again the master view table has returned all the way to the top. I've had a look at the following 2 questions that are similar.
How can I get the UITableView scroll position so I can save it?
Setting scroll position in UITableView
I still can't get these to work. I'm not the most experienced coder so I'm really struggling with this.
I know things like viewWillDisappear and viewDidAppear need to be changed, but I just really can't get much further than that.
On this table I have a reloadData feature so it is possible to pull down the latest data from the server and also a working search bar.
Anyway, a helping hand would be great. Thanks,
Luke
See here you have to first save the scrolled position of tableView i.e. contentOffset of tableView and then reuse it when you are coming back to tableView.
1)When and where you will save it :
When : At the point, when you are drilling down to detailViewController save the contentOffset of tableView
How : float verticalContentOffset = tableView.contentOffset.y;
2) How will you set tableView back to the same scrolled position :
[tableView setContentOffset:CGPointMake(0, verticalContentOffset)];
Hope this will help you.
Sorted!
With a bit of inspiration from Desdenova, whilst at work I had a good think about it and realised what it could be. Remembering that I had a search bar, I had implemented the following code a few months ago to hide it:
[self.tableView setContentOffset:CGPointMake(0,-20) animated:NO];
In naivety I put that in viewDidAppear rather than viewDidLoad. Obviously, this did hide the search bar, but with it being in the wrong void command it did it every time the masterDetailView returned to the top of the stack. So, after moving the above code to viewDidLoad it now still hides it, but only the once.
I'm just spelling it out like this for other beginners, like myself, who may come across the same problem and may just save their sanity!
Thanks to you all for your ideas that helped me out.
+1 to you all!
If anyone is wondering, I tried the solution by Prashant N and it worked. However reloadData don't actually reset the scroll position anymore now, so I didn't have to do anything other than reloadData.
My solution to this problem consisted in scrolling the table to the indexrow of the last item.
private func scrollToItem(item:Int, section:Int bottom:Bool = true, animated:Bool = false) {
let indexPath = NSIndexPath(forRow: item:Int-1, inSection: section)
var position = UITableViewScrollPosition.Bottom
if (!bottom) { position = UITableViewScrollPosition.Top }
self.tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: position, animated: animated)
}
For some reason this was halfway working for me (sometimes the position would only be approximate). I finally used the following a priori less clean solution
NSIndexPath *firstVisibleIndexPath = [[self.tableView indexPathsForVisibleRows] objectAtIndex:0];
[self.tableView scrollToRowAtIndexPath:self.firstVisibleIndexPath atScrollPosition:UITableViewScrollPositionTop animated:NO];
self.firstVisibleIndexPath = firstVisibleIndexPath;
which worked better.
As mentioned in other comments, scrolling to the top on Back navigation in a UINavigationController is not the default behavior.
Another cause might be that you are setting a cell near the top of the table as first responder in viewWillAppear, e.g. a search box or edit field near the top of your table. UITableViewController will scroll a first responder into view automatically, which is nice. As long as that's what you're trying to do. :) Take care to not set first responder in viewWillAppear unless that's what you want. Cheers, AZ
My decision for a collection:
CGFloat oldCollectionViewHeight = self.messageCollectionView.contentSize.height;
[self.messageCollectionView reloadData];
[self.messageCollectionView layoutIfNeeded];
CGFloat newCollectionViewHeight = self.messageCollectionView.contentSize.height;
if (oldCollectionViewHeight) {
self.messageCollectionView.contentOffset = CGPointMake(0, newCollectionViewHeight - oldCollectionViewHeight);
}
For the table, the principle is the same.
You don’t need to do anything, while you are in the same view controller, your position will be the same. I’m afraid that somewhere in your view controller is being called a reloadData. Search for some method calling scrollToRowAtIndexPath.

Search freezes in UISearchBar with searchDisplayController

I have a UISearchDisplayController working nicely with a UISearchBar. shouldReloadTableForSearchString correctly returns results as the user types, but when the user hits the Search button on the keyboard and searchBarSearchButtonClicked is triggered, something odd happens after the final search results correctly display and the user hits Cancel on the search bar. Once the user reactivates search, the search opens but the cursor doesn't blink, the search results don't display and the keyboard looks locked on every keypress as shown in the attached image. There should be results for "Test", but nothing is happening and something seems to be held up b/c the last pressed key ("T") isn't going back down to the keyboard.
I'm holding off on including code b/c there are a lot of moving parts, but if any code would help, i can quickly include it. Thanks for your help.
UPDATE: it's not just after the user submits the query - if they've touched the resulting searchDisplayController.searchResultsTableView after inputting a query to scroll down through the results, and then hit Cancel, they'll see the frozen cursor and broken search once they activate the searchBar again (same image applies).
SECOND UPDATE: this only happens when I hide / unhide the navbar while search is active in viewWillLayoutSubviews. Any ideas? Really appreciate any help!
-(void)viewWillLayoutSubviews {
if (self.searchDisplayController.isActive && !profileSelected) {
[self.navigationController setNavigationBarHidden:YES animated:YES];
}
else {
[self.navigationController setNavigationBarHidden:NO animated:YES];
}
}
LAST UPDATE: when hide/unhide code is placed into searchDisplayControllerWillBeginSearch and searchDisplayControllerWillHideSearch respectively, the searchBar incorrectly unhides 20px below navbar:
fixed it by adding this code:
-(void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
[self.searchDisplayController.searchBar becomeFirstResponder];
}
UISearchDisplayController is using UITableView to show search results. Whenever you scroll or new cells are loaded, viewWillLayoutSubviews is getting called. This is causing the app to freeze. Try moving you setNavigationBarHidden code in a separate method triggered by some other action.

UISearchDisplayController jumps to the left

I've seen the question at some places, but not one helped me. Been searching for a while now, so I'll just ask it here.
I have a problem with UISearchDisplayController. The tableView this is working on doesn't take the whole screen, only the right side:
When I tap the searchBar on top it jumps to this:
And when I actually search, this is what I get:
I've tried several 'solutions' like:
- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController
*)controller {
controller.searchBar.frame = CGRectMake(300, 20, 744, 44);
}
- (void)searchDisplayController:(UISearchDisplayController *)controller didShowSearchResultsTableView:(UITableView *)tableView {
tableView.frame = CGRectMake(0, 0, self.carListDropbox.frame.size.width,
self.carListDropbox.frame.size.height);
}
- (void)searchDisplayController:(UISearchDisplayController *)controller willShowSearchResultsTableView:(UITableView *)tableView {
tableView.frame = self.carListDropbox.frame;
}
They don't seem to help AT ALL. Is there any other way I can lock the searchBar (and UISearchDisplayController) into a view?
Thx!
I attempted to make search controllers work in this way and had many problems with the search results tableview not being in the right position and the search bar not being in the right position either. It seems apple's default design for these animates it to the top and does not really give you much information or control over how this is done.
While I'm not sure if there is a way to lock the searchBar into the view(and get the searchResultsTableView to position properly all the time) because there may be a way to do this that I don't know, but I think it is not worth the trouble.
Instead, I'd recommend making your own search bar and searchresultstableview which you can control, animate and position however you'd like whenever you want to, no headache. Make your searchresultstableview hidden until they enter the text field or start typing in it, then show it as desired. If you want it to look the same you'll have to draw your own search icon and search bar which isn't too difficult with UIBezierPath, or you can add your own images.

UIRefreshControl behaves differently after adding UISearchBar

I'm using a UITableViewController subclass in iOS 7.
Before I added the search bar as the table view's tableHearerView, the UIRefreshControl worked as I expected: I triggered beginRefreshing in viewDidLoad and I could see it spinning every time I entered this screen.
After I added the search bar, I can't see UIRefreshControl spinning when I enter this screen. Everything else seems to work fine, e.g pulling down will show the spinning UIRefreshControl.
Did I use the 2 widgets in right way? How to fix this issue so I can see the spinning like what I saw before adding the search bar?
Thanks a lot in advance!
It looks like if you invoke the beginRefreshing method manually you also need to set the offset of the tableView manually.
Here is the solution in Objective-C:
[self.tableView setContentOffset:CGPointMake(0, -self.refreshControl.frame.size.height) animated:YES];
and here the solution in Swift:
self.tableView.setContentOffset(CGPointMake(0, -self.refreshControl!.frame.size.height), animated:true)

Remembering scroll position on UITableView

I have a bit of a problem with my iOS app in xcode. I have a UITableView that loads a few hundred cells. When I scroll down to a specific cell and drill down to detailedviewcontrollers and return again the master view table has returned all the way to the top. I've had a look at the following 2 questions that are similar.
How can I get the UITableView scroll position so I can save it?
Setting scroll position in UITableView
I still can't get these to work. I'm not the most experienced coder so I'm really struggling with this.
I know things like viewWillDisappear and viewDidAppear need to be changed, but I just really can't get much further than that.
On this table I have a reloadData feature so it is possible to pull down the latest data from the server and also a working search bar.
Anyway, a helping hand would be great. Thanks,
Luke
See here you have to first save the scrolled position of tableView i.e. contentOffset of tableView and then reuse it when you are coming back to tableView.
1)When and where you will save it :
When : At the point, when you are drilling down to detailViewController save the contentOffset of tableView
How : float verticalContentOffset = tableView.contentOffset.y;
2) How will you set tableView back to the same scrolled position :
[tableView setContentOffset:CGPointMake(0, verticalContentOffset)];
Hope this will help you.
Sorted!
With a bit of inspiration from Desdenova, whilst at work I had a good think about it and realised what it could be. Remembering that I had a search bar, I had implemented the following code a few months ago to hide it:
[self.tableView setContentOffset:CGPointMake(0,-20) animated:NO];
In naivety I put that in viewDidAppear rather than viewDidLoad. Obviously, this did hide the search bar, but with it being in the wrong void command it did it every time the masterDetailView returned to the top of the stack. So, after moving the above code to viewDidLoad it now still hides it, but only the once.
I'm just spelling it out like this for other beginners, like myself, who may come across the same problem and may just save their sanity!
Thanks to you all for your ideas that helped me out.
+1 to you all!
If anyone is wondering, I tried the solution by Prashant N and it worked. However reloadData don't actually reset the scroll position anymore now, so I didn't have to do anything other than reloadData.
My solution to this problem consisted in scrolling the table to the indexrow of the last item.
private func scrollToItem(item:Int, section:Int bottom:Bool = true, animated:Bool = false) {
let indexPath = NSIndexPath(forRow: item:Int-1, inSection: section)
var position = UITableViewScrollPosition.Bottom
if (!bottom) { position = UITableViewScrollPosition.Top }
self.tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: position, animated: animated)
}
For some reason this was halfway working for me (sometimes the position would only be approximate). I finally used the following a priori less clean solution
NSIndexPath *firstVisibleIndexPath = [[self.tableView indexPathsForVisibleRows] objectAtIndex:0];
[self.tableView scrollToRowAtIndexPath:self.firstVisibleIndexPath atScrollPosition:UITableViewScrollPositionTop animated:NO];
self.firstVisibleIndexPath = firstVisibleIndexPath;
which worked better.
As mentioned in other comments, scrolling to the top on Back navigation in a UINavigationController is not the default behavior.
Another cause might be that you are setting a cell near the top of the table as first responder in viewWillAppear, e.g. a search box or edit field near the top of your table. UITableViewController will scroll a first responder into view automatically, which is nice. As long as that's what you're trying to do. :) Take care to not set first responder in viewWillAppear unless that's what you want. Cheers, AZ
My decision for a collection:
CGFloat oldCollectionViewHeight = self.messageCollectionView.contentSize.height;
[self.messageCollectionView reloadData];
[self.messageCollectionView layoutIfNeeded];
CGFloat newCollectionViewHeight = self.messageCollectionView.contentSize.height;
if (oldCollectionViewHeight) {
self.messageCollectionView.contentOffset = CGPointMake(0, newCollectionViewHeight - oldCollectionViewHeight);
}
For the table, the principle is the same.
You don’t need to do anything, while you are in the same view controller, your position will be the same. I’m afraid that somewhere in your view controller is being called a reloadData. Search for some method calling scrollToRowAtIndexPath.

Resources