Changing cell height scrolls it off screen - ios

I'm trying to expand a cell, by implementing different heights in heightForRow method. Everything works mostly ok, but when I'm expanding cell it somehow scrolls off screen. Here is what I mean (note feedback section):
As you can see there is feedback cell, and when I tap on smileys I want it to expand. I change the state and reload the row. This is what happens:
As you can see, the section completely scrolled off the screen and it is not visible.
If you scroll down, it is fine right there:
Here is the code that I use:
Method that triggers cell expansion:
self.feedbackCellStatus = FeedbackCellStatusExpanded;
NSIndexPath *indexPathToUpdate = [NSIndexPath indexPathForRow:0 inSection:[self indexOfSection:ReportSectionFeedback]];
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:#[indexPathToUpdate] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView endUpdates];
Here is my height for row:
if (indexPath.section == [self indexOfSection:ReportSectionFeedback]) {
if (self.feedbackCellStatus == FeedbackCellStatusStarting) {
return FeedbackHeightStarting;
} else if (self.feedbackCellStatus == FeedbackCellStatusExpanded) {
return FeedbackHeightExpanded;
} else if (self.feedbackCellStatus == FeedbackCellStatusDone) {
return FeedbackHeightDone;
}

Related

In UItableview How to Expand and collapse particular TableviewCell dynamically

In my app I am trying to display Mkmapview in UITableView. When I tap the cell, it has to expand and show the map. Then if I tap another cell, it should act again expand and show gallery view , the previous cell must collapse and map should be hide.
thanks in advance,
You have to keep track of the state (or height) of the expanding/collapsing cell. Then report that height in tableView:heightForRowAtIndexPath:. Then add the code below to trigger the resizing.
[self.tableView beginUpdates];
[self.tableView endUpdates];
For example:
- (void)toggleMapCell {
_mapCellExpanded = !_mapCellExpanded;
if (_mapCellExpanded)
_mapCellHeight = 200.0;
else
_mapCellHeight = 44.0;
[self.tableView beginUpdates];
[self.tableView endUpdates];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if ([indexPath isEqualTo:_mapCellIndexPath])
return _mapCellHeight;
else
return 44.0;
}
If you have to re-layout the cell's content. I think the best place is to do it in the cell's layoutSubviews.

XCode iOS7 - Dynamic cell with UITextView like Reminder App

I need to create an application that have the same behavior as built-in Reminder App. There are some problems to create this:
Cells that have dynamic height and "grow" as the content of the UITextView
Select the touched cell
Refresh the height of the cell when the user has edited the content(on the fly)
I've already solved the dynamic height, using some trick.
The problem that remains is:
How to know which cell the user has selected if the cell is "fully" with the UITextView ?
Right Now i've used the method textViewDidBeginEditing to know the cell and scroll the UITableView to it:
- (void)textViewDidBeginEditing:(UITextView*)textView
{
MemoViewCell* cell = (MemoViewCell *)[self parentCellFor:textView];
if (cell)
{
NSIndexPath* indexPath = [self.tableView indexPathForCell:cell];
currentIndexPath = indexPath;
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
}
}
- (UITableViewCell*)parentCellFor:(UIView*)view
{
if (!view)
return nil;
if ([view isMemberOfClass:[MemoViewCell class]])
return (UITableViewCell*)view;
return [self parentCellFor:view.superview];
}
How to refresh the cell height without lost the focus?
To this, i've used this method:
-(void)textViewDidChange:(UITextView *)textView
{
NSMutableDictionary *dataSourceItem = [self.model.dataSource objectAtIndex:currentIndexPath.row];
[dataSourceItem setObject:textView.text forKeyedSubscript:#"body"];
[self.model.dataSource setObject:dataSourceItem atIndexedSubscript:currentIndexPath.row];
[self.tableView beginUpdates];
[self.tableView endUpdates];
}
When the text change, i get the new text, i change it in the Model and i call beginUpdated and endUpdates.
Sure, this works, but all is extremly slow... do you have some idea to to this in a more elegant way and maybe... efficient?
If i call reloadRowsAtIndexPaths: i lost the focus on the cell.
First of all, if you use the delegate method - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath; in your dynamic height trick, remember to implement this method along - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath;, it helps a lot in terms of performance.
Then to focus on your specific project, if I correctly understood your goal, what you really want is to update the layout of your table view only when your text view is modified. Currently you're updating it at each text change. You might consider using a condition inside -(void)textViewDidChange:(UITextView *)textView, such as :
if ([textView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height !=
textView.frame.size.height) {
[self.tableView beginUpdates];
[self.tableView endUpdates];
}
The condition given as example will work only if your existing cell layout respects the intrinsic content size of the text view, otherwise you will need to adapt the condition.

UITableView jumps to the top when a cell is deleted and then goes back to his position

I'm trying to code a feed so it's just a basic UITableView with one row per section and as many sections as posts.
If I select a cell the tableView displays a cell in the row 1 in the same section than the selected cell, and if I re-select the cell or scroll the tableView the row 1 is deleted.
The problem is that if i select the first cell and then scroll to the bottom (like a pull to refresh), the tableView scroll while the animation of the deleting cell is done then at the end of the animation jumps to the top of the screen and then return where he was.
I don't know if that was clear.
Here's my scrollViewDidScroll
def scrollViewDidScroll(scroll_view)
return if #can_scroll_comments
hide_comments unless #comment_triggered_for == -1
end
def hide_comments
feed_view = layout.get(:feed_view)
section = #comment_triggered_for
#comment_triggered_for = -1
feed_view.deleteRowsAtIndexPaths([NSIndexPath.indexPathForRow(1, inSection: section)], withRowAnimation: UITableViewRowAnimationFade)
end
in objective-c it should be something like
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (_can_scroll_comments) {
return ;
}
if (_comment_triggered_for != -1) {
[self hide_comments];
}
}
- (void)hide_comments: {
section = _comment_triggered_for
_comment_triggered_for = -1
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:1 inSection:section]] withRowAnimation:UITableViewRowAnimationFade];
}
Thanks for the help :)

Why does UITableView only auto-scrolls when first character is typed?

I have a UITableView cell with dynamically growing UITextView. The height of the cell is getting set correctly. However, for some reason auto-scroll doesn't adjust the offset when I hit Enter and begin a new line (see image A) but only when I type the first character on that line (see image B). Any thoughts on this?
EDIT:
I'm using HPGrowingTextView and taking the height that its delegate gives me. It fills the entire cell. I measured the screenshot against the value it gives me and it matched. Below are the pertinent methods:
-(void)growingTextView:(HPGrowingTextView *)growingTextView willChangeHeight:(float)height {
_messageHeight = height;
// this will trigger cell height resize
[self.tableView beginUpdates];
[self.tableView endUpdates];
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == kMessageRow) {
return _messageHeight;
}
return 50;
}
Image A: Cursor is partially hidden when starting a new line
Image B: Now auto-scroll makes the adjustment once first character is received
The issue wasn't with the growing text view but rather with the UITableView auto-scroll which doesn't seem to fire when detecting the return key. So my solution was to check for the new line character manually and to force a scroll to the bottom of the cell.
- (void)growingTextViewDidChange:(HPGrowingTextView *)growingTextView {
NSString *text = growingTextView.text;
NSInteger endIndex = text.length - 1;
if (endIndex >= 0 && [[text substringFromIndex:endIndex] isEqualToString:#"\n"]) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:textViewSection];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:NO];
}
}

Changing a specific uitableviewcell row height while scrolling a uitableview

I have a UITableview with 2 sections, 1 row in the 1st section, and a variable amount of rows for the second section. When the user scrolls the table up (finger moving upwards), then the tableview does it's default thing, but when the user is at the top of the uitableview and scrolls down (finger moving downwards) then it should look like the first cell in the first section height increases as much as the user scrolls down (and releasing the touch will change the height of the row back to it's original height of 100). I tried
-(void)scrollViewDidScroll:(UIScrollView*)scrollView{
if(scrollView.contentOffset.y < 0){
[mainTable reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection: 0]] withRowAnimation:UITableViewRowAnimationNone];
}
}
-(CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath{
if(indexPath.section == 0 && tableView.contentOffset.y < 0){
return -tableView.contentOffset.y+100;//Default height is 100
}
}
but the reloadRows method resets the contentOffset to 0 so the tableview just stutters when i pull down. It seems like if this doesn't work, then i'll have to write everything on a UIScrollView and it seems like a huge pain without recyclable cells.
Does anybody have any suggestions?
No need to reload the row, i just changed the frame directly. Make sure you set the cell.layer.masksToBounds = YES and make the subViews in the cell to be larger than the original cell height.
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
if (mainTable.contentOffset.y < 0) {
UITableViewCell *cell = [mainTable cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
float rawr = mainTable.contentOffset.y;
cell.frame = CGRectMake(cell.frame.origin.x, rawr, cell.frame.size.width, 100-rawr);
}
}

Resources