Remembering scroll position on UITableView - ios

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.

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.

Changing the zPosition of searchResultsTableView

I have a UISearchBar working to dynamically show matching results from a list, but having a nightmare trying to stop the searchResultsTableView from obscuring the resultant UIView, which animates in from the right, when the result is tapped.
The magenta view, (including its shadow subview) and the solid black view should be above the list.
I've tried…
self.searchDisplayController.searchResultsTableView.layer.zPosition = 0;
recipeMeasuresView.layer.zPosition = 1;
recipeListView.layer.zPosition = 2;
…but it's messing up the gestures attached still not displaying the views in the correct order. I've also tried…
[self.view sendSubviewToBack:_searchBar];
[ingredientListView bringSubviewToFront:ingredientListView];
…still no joy. Incidently, I'm also adding – amongst other things – [_searchBar resignFirstResponder]; to my
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
I'm very much an objective-C newbie so all help greatly appreciated.
In case anybody else stumbles across this with similar problems it seems that the issue is due to the searchDisplayController adding it's own view(s) at the top of the stack, therefore obscuring anything that was added to the storyboard.
There would be no way to push anything up or down to change the order because the searchDisplayResultsTable was being added by a different view controller.
The solution I used was to add the views that were being hidden programatically, meaning I could add them as subviews to different parent views depending on what was happening. Probably not the best solution but it does appear to work.

iOS development Animating Table view custom cell content

I am working on new application and i would like to have custom table view. I need to have cell that have 2 labels 1 check box and 2 buttons. The problem i have is that 2 buttons need to be shown only if user press edit button on top. I made all this to work but i have some problem with reusable cells or something like that.
I made custom cell class so i can assign data to it.
First state is: First state on img
Then when user press edit button on top i need everyting to animate and come to right place.
I want text to animate to right to make space for button, delete button needs to come animated from left side and edit butom to come in animated from right side.
This is what i want to get after animations are done: Second state on img
I made all this to work but now i have problem that first 2 cells that will come on screen after i scroll down are not effected by my code :(
This is what i get: Third state on img
i will post my project code here and if some1 can help me with it i would be more then thrilled. I point me to right way to do this.
Code downoald: https://www.mediafire.com/?g1g6d7h33mpkyt7
and i will post some code here that i think is crucial to my problem:
for animations i use:
[cell.infoView setFrame:CGRectMake(20, CGRectGetMinY(cell.infoView.frame), CGRectGetWidth(cell.infoView.frame), CGRectGetHeight(cell.infoView.frame))];
[UIView animateWithDuration:0.4
delay:0
options:UIViewAnimationOptionCurveEaseIn
animations:^{
[cell.infoView setFrame:CGRectMake(70, CGRectGetMinY(cell.infoView.frame), CGRectGetWidth(cell.infoView.frame), CGRectGetHeight(cell.infoView.frame))];
}
completion:nil];
for cell init i use:
CICustomCell *cell;
cell = [tableView dequeueReusableCellWithIdentifier:CellTableIdentifier];
if(cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"HCICustomCell" owner:nil options:nil];
cell = [nib objectAtIndex:0];
}
cell.itemName = [dwarves objectAtIndex:indexPath.row];
cell.quantity = 25.99;
for table init i use:
UITableView *tableView = (id)[self.view viewWithTag:1];
tableView.rowHeight = 60;
UINib *nib = [UINib nibWithNibName:#"HCICustomCell"
bundle:nil];
[tableView registerNib:nib forCellReuseIdentifier:CellTableIdentifier];
img: http://i270.photobucket.com/albums/jj109/lazardj/scsimg.jpg~original
EDIT:
I also tried something now. If i start my activity then scroll down a bit so i get some new cells i dont have this problem. So it must be something with creating cells or reusability of cells or something like that. I am new to ios development so i cant figure this out on my own :( so please help :) Thanks
In your cellForRow function in your tableview delegate you need to deal with the location of your labels. So every time you request a new (or reused) cell you need to check whether you are in edit mode and then set the labels frames accordingly.
It appears as you are already doing this for the buttons, as they show up in the proper place, but the labels are being re-used at their initial locations (when they were released by the tableview).
I've had a look at your project, and the problem appears to stem from using AutoLayout. The automatic constraints appear to be interfering with your view layouts. If you go to your HCICustomCell.xib file and click on the file inspector tab, you'll see a checkbox for "Use Autolayout". Uncheck this and then set the auto-resizing constraints manually for each view in the Size Inspector tab. I've uploaded a revised version of your project here.
SOLUTION:
I done some more work on this. Tried solutions you provided me but there are still times when it gets bugged so i came with my own one. I figured out that the problem is that you cant move view in cell on first init but you can show hide them. So i decided to try to make same info view on place where it needs to be when enable is on. When enable is off its hidden and when enable is on it shows up. This is what fixed my problem :) I know its not the smartest way to do things but i managed to do what i wanted and its not messing performances of application.
This is project with fixed bugs. If any1 want can use it :)
Thanks for all your time and suggestions.
Project: https://www.mediafire.com/?uhatbh8c20xu49v

iOS table cells with fixed images

I'm developing an ios app and am trying to achieve an effect in a tableview like the following website: http://www.poormet.com/
There is a couple of ways I have thought about this. I know you can set the background of the tableview which remains fixed and then you could possibly swap the images as the text box covers the image. This is limited though as you can only have one image on the screen at a time which is not what I'm after.
I also thought about pushing the image down for each cell as the cell moves up, but for this case I couldn't set the frames position in the scrollViewDidScroll method(which I used to obtain the frames actual position in the tableview).
I was also wondering if there was anything similar in ios to what you have with div's in html where you can specify an image to be fixed.
How would I go about doing this? If you guys need any more information let me know, I'm new to posting on this site.
Thanks.
I think you should be able to do this through scrollViewDidScroll. I'm guessing you already have subclassed UITableViewCell and made your own, so heres a thought:
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
for(UITableViewCell *cell in [yourTableView visibleCells])
{
//I haven't tried this `convertRect` method, and the views might be in the
//wrong order, but I'm sure you'll figure it out. It should solve this.
CGRect position = [yourTableView convertRect:cell.frame toView:self.view]
[((YourCustomCell*)cell) updateImage:position];
}
}
Then in your custom cell class, add a method named -(void)updateImage:(CGRect)position; which will now contain the location of the cell, and you can move the image whatever way you want, as I'm guessing you already have a method for. I.E:
-(void)updateImage:(CGRect)position
{
//change the location of the image inside self.imageView here
}

iOS: Using modal pageFlip makes strange cell animation in UITableViewController

I wanted to show a Settings view, so I figured I could use the pageCurl modal style. I have a UIViewController that I am presenting from:
Settings *settings = [[[Settings alloc] initWithStyle:UITableViewStyleGrouped] autorelease];
settings.view.backgroundColor = [UIColor scrollViewTexturedBackgroundColor];
settings.modalTransitionStyle = UIModalTransitionStylePartialCurl;
settings.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentModalViewController:settings animated:YES];
When the page curls, to reveal my UITableViewController below, the cells subviews (labels and accessory views) seem to animate into position, which looks horrible:
The strange thing is, is that the animation never happens to the top cell in a section. This does not happen with other modalTransitionStyle's so I am wondering why this could be happening. It is really becoming frustrating because I cannot figure out how to stop this from happening.
Ideas?
If you set the autoResizingMask property of the tableView to UIViewAutoresizingNone, I think this won't happen. This may be a little bug in the page curl animation.
I've noticed that the direction of this weird animation (which also happens to UIButtons), depends on the Alignment chosen in the Control section of the object's Attributes inspector (in Interface Builder). I've been tinkering with all attributes all evening and have found no solution yet. :(
Edit: so, I had three UIButton in my view (and one UIPickerView) that where doing this weird behavior at the same time. I created a property linking to ONE of the UIButtons. Then, in the viewDidLoad of this view's controller I added the following line:
_firstAffectedButton.titleLabel.autoresizingMask = UIViewAutoresizingNone;
And that fixed it for me, for all the buttons and the picker!! :? Weird, right?
Can anyone explain why this is working? I have the feeling I'm doing something stupid to fix this, but I can't see what it is.
Edit 2: Turns out there was a better and cleaner solution to this problem. See this post.

Resources