iPhone - having selected cell move to top of uitableview - iphone

I looked for this problem and I don't believe I could find an answer. I have a tableview of custom cells that when clicked, the selected cell pushes a new cell with information. I was wondering if anyone had an idea of how to push the selected cell to the top of the uitableview, or make it fill up the entire tableview.
My uitableview only takes up half of the screen, and I wish for when the cell is selected that it only take up that half of the screen, and the user is still able to scroll the cell (if that makes sense)?
Any suggestions would be appreciated, it was somewhat difficult to describe what I am looking for, so if anyone needs clarification please do not hesitate to ask me.

in cellForRowAtIndexPath, you need to place this in after you have created your cell
[tableView scrollToRowAtIndexPath:selectedCellIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
This did the trick for me with the custom height of the cells as well.

In my app I have a bunch of cells that expand to be larger when clicked; and only 1 cell can be expanded at a time. I basically keep track of the current selected indexPath, and then in heightForRowAtIndexPath: check to see if this is the selected sell; if it is I return a larger height.
Then, in didSelectRowAtIndexPath: I just set the current indexPath, and reload both the new cell and the previous one. This sounds similar to what you are looking for... would that work?

To move the selected cell to the top of the tableview, you could store the selected cell's index in an instance variable in didSelectRowAtIndexPath, and then call [tableView reloadData].
In your datasource's tableView:cellForRowAtIndexPath: method, you would ensure that the selected cell is returned for index 0 and all cells prior to the selected cell are returned for their index + 1.

If you are looking to move the cell, this is a base you could start from.
-(void)moveIndexPathToTop:(NSIndexPath *)pathToMove
{
[myTable deleteRowsAtIndexPaths:[NSArray arrayWithObject:pathToMove] withRowAnimation:UITableViewRowAnimationFade];
NSIndexPath *firstRow = [NSIndexPath indexPathForRow:0 inSection:0];
[myTable insertRowsAtIndexPaths:[NSArray arrayWithObject:firstRow] withRowAnimation:UITableViewRowAnimationFade];
}
This will move the row as far as the UITableView is conserned. Of course you'll need to match the new order in the data source also. (Like changing the order in your array of data)
Also, you'll probably want to scroll the table to the top when you do this.

Related

UITableView won't reload contentSize

I have a UITableView, that add's some data after the UITableView reloaded for the first time, but I can't scroll down to the new data if I scroll I see the new data but then it scrolls back automatically, and yes I reloaded my UITableView, so I checked my UITableView contentSize and it won't change after the reload but after I go to another view (UINavigationController) and pop back the UITableView contentSize does change and it works! How can I fix this?
Thanks!
I had a similar issue and solved it using the same technique as Daan (as far as I can tell).
In my case I was using a static UITableView that had some of its rows and sections hidden initially (by setting appropriate return values from numberOfSectionsInTableView: and tableView:numberOfRowsInSection:). I was pushing a VC onto the nav stack to collect additional data which I would then use to fill in the hidden tableview sections, calling reloadData on the tableview to refresh it.
This worked fine in iOS7, but in iOS6 the tableview's contentSize.height never changed from its initial value (218 pts) to the taller value (504 pts) derived from the addition of the new sections. As such, you could not scroll to the content at the bottom of the tableview. Trying to force the contentSize did not work as it was immediately set back to 218.
Changing the tableView's contentOffset allowed me to scroll to the bottom of the content, but if you tapped the UITextField in the last cell, it would whip off screen as the keyboard was shown.
I finally was able to come up with a solution that worked in both iOS6 and iOS7 without issue. I used the old beginUpdates / insert or delete rows and sections / endUpdates methods of UITableView, as follows:
// change the tableView's data source to reflect insertions/deletions
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:#[ [NSIndexPath indexPathForRow:1 inSection:0] ] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView insertSections:[NSIndexSet indexSetWithIndexesInRange:NSRangeFromString(#"1,3")] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView endUpdates];
As you can see, in this particular case I had to remove a row from the first (and only) section and add three sections to the end of the tableview.

UITableView scrolling to last cell only displays half of the cell

I want to scroll to the bottom of my tableview that contains custom cells.
Here is the code I am using to scroll:
NSIndexPath *lastMessage = [NSIndexPath indexPathForRow:[self.conversation.messages count]-1 inSection:0];
[self.messageTable scrollToRowAtIndexPath:lastMessage atScrollPosition:UITableViewScrollPositionTop animated:YES];
This scrolls the view; however only the very top of the last cell is visible with ~3/4 of the cell still below the fold that I have to manually scroll down to. Any ideas on how to fix this?
Turned out to be a timing issue. The tableview hadn't fully rendered yet when I called that method from viewdidload (contentsize of 0). Calling this method in viewDidAppear works brilliantly though.
It seems like the UITableView is confused about how big your cells are. Set the rowHeight property on the UITableView to the height of your custom cell.

How can I set the UITableViewCellAccessory for a chosen row? (iPhone/iPad)

I need a way of setting the UITableViewCellAccessory for any row. However the catch is that I need to be able to do it OUTSIDE of the UITableView delegate methods.
I have tried this, but it doesn't show up the accessory.
[[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathWithIndex:1]] setAccessoryType:UITableViewCellAccessoryCheckmark];
If it makes any difference I created the UITableView in IB in a storyboard. The data is static, and I'm using a grouped table style with only one section.
Please can someone help me out?
If your table view is scrolled so the cell in question may sometimes scroll out of view and then back into view, you should manage the content of that cell only from within the UITableView method cellForRowAtIndexPath:. The reason is that when cells are redrawn, the tableview object calls this method to make sure that visible cells are properly rendered. (Cell that are not visible don't need to be rendered at all.)
That being said, this is where you should handle the cell content, even if the table view doesn't scroll the cell in question out of view. It wil lmake you life a lot easier if you follow this design pattern when working with table views.
Inside that method, you can test (using if statement, for example) the value of the indexPath.section and indexPath.row so that you can configure the specific cell the way you want it. This includes putting in the accessory.
Always use [NSIndexPath indexPathForRow:inSection:] when working with table views.
You can figure out what indexPath you need the checkmark on and then use something like this
UITableViewCell * cell = [tableView cellForRowAtIndexPath:someIndexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;

how to center uitableview selection with indexpath value

I am saving the indexPath selection from a subview and passing it to the parent view with delegates. When I got back to my subview from my main view I pass the indexPath back to it and show the user which cell they previously selected with a tick in the accessory view of the tableviewcell.
One problem being if the user has selected a cell out of a fairly big list its hard to find the cell they selected again incase they wanted to change it (being that they made a mistake)
I would like to know if their is a way to use indexPath or something similar to center the previously selected cell of the uitableview to the center of the screen?
UPDATE::
Here is a graphical view of what I am trying to achive to make it abit more understandable..
step one : select cell then go to subview and select the cell (value) you want to pass back to main view (save indexPath of selected cell)
step two: user either wants to change his selection or made a mistake and was ment to select the cell below the one they chose... repeat previous steps but display previously selected cell in the center of the view..
Have you tried the following function
[tableView scrollToRowAtIndexPath: atScrollPosition:UITableViewScrollPositionMiddle animated:YES]
a UITableView is a subclass of UIScrollView - try setting the Content Offset (figure out how much with the cell height and indexPath).
[tableView setContentOffset:CGPointMake(0, indexPath.row*cellHeight) animated:YES];
should work. You might want to do the math a little differently.

temporarily prevent a UITableViewCell from being recycled

My UITableViewCells can accept input of data. While working in one cell, it would be perfectly natural for the user to want to scroll up, check something in another cell, then return to the first cell and continue the data entry.
The problem is that this will frequently cause the UITableView to recycle the cell, which wreaks havoc in my program.
Is there any way to temporarily tell iOS not to recycle the cell?
Once the data entry is done, I am fine if it is recycled.
I should add that the data entry uses a custom keyboard. So first responder status is not an issue.
Give a different cellIdentifier to the cells that are significantly different. If the cell at the bottom has its own identifier, then when the user scrolls to the bottom, it won't recycle your cell from the top. However, this will still preserve your cell at the top in the reuse queue, so that when you scroll back to the top, you won't need to recreate it.
There's no way how to prevent cell recycling if you do use dequeueReusableCellWithIdentifier: method of UITableView in a common way.
If you would like to do this, you should implement it on your own in UITableView's data source protocol method - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath.
As Chiefly Izzy said, it's not a common way to work. And going against the way the lists work may cause problems. If you want to reduce your problem, keep the content of your cell in memory and use this saved content to refill the cell when willDisplayCell is called instead of rebuilding the whole thing from start each time.
Gendolkari's solution gave me an idea for temporarily removing a cell from the dequeue cycle. It does involve setting a read-only value using KVC, so it's not for the truly hack-adverse.
When you first want to remove the cell from the cycle, change the reuseIdentifier for that particular cell. We want to be able to find the cell later so rename it something that we can index against. I found [NSIndexPath description] to be useful here. The reuseIdentifier is a read-only property, but this is Objective-C, and we have KVC:
[cell setValue:[[self.tableView indexPathForCell:cell] description] forKey:#"reuseIdentifier"];
Now whenever we reuse a cell in the cellForRowAtIndexPath:
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:#"cellIdentifier"];
we won't get back this particular cell because we have changed the reuseIdentifier.
However, if we scroll down then scroll back up, we probably want to display the original cell that we removed from the dequeue cycle. To do this when we are reusing a cell first attempt to dequeue a cell based on indexPath, and if we can't find that attempt to dequeue a cell simply based on the basic cell identifier string:
UITableViewCell *cell;
cell = [self.tableView dequeueReusableCellWithIdentifier:[indexPath description]];
if (!cell) cell = [self.tableView dequeueReusableCellWithIdentifier:#"cellIdentifier"];
When you want to put that cell back into the dequeue cycle, simply change the reuseIdentifier back to the original value:
[cell setValue:#"cellIdentifier" forKey:#"reuseIdentifier"];