Table View height changes on tap or when popped back to - ios

I have a table view that loads 3 custom cells. 1 custom cell has an ImageView in it, and it seems to be the culprit of the table view moving when any cell is tapped.
This is what I've tried, but it hasn't worked.
If I use a static value (i.e. return 180) it works just fine, but anything other than that the table view jumps.
Anyone know why? Thanks!
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
id model = self.Model[indexPath.row];
if ([model isKindOfClass:[FR self]]) {
ListTableViewCell *cellOne = [tableView dequeueReusableCellWithIdentifier:#"1Cell" forIndexPath:indexPath];
if (!cellOne) {
cellOne = [[ListTableViewCell alloc] init];
FR *fD = (FR *)model;
NSString *title = [NSString stringWithFormat:#"%#", fD.title];
NSString *dateString = [self timeSincePublished:fD.pubDate];
NSString *description = [self removeHTMLTags:fD.description];
NSString *link = [NSString stringWithFormat:#"%#", fD.link];
cellOne.labelHeadline.text = title;
cellOne.labelDescription.text = description;
cellOne.labelPublished.text = dateString;
}
// Make sure the cell's frame is updated
[cellOne setNeedsLayout];
[cellOne layoutIfNeeded];
CGFloat heightOne = [cellOne.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
return heightOne + 2;
} else if ([model isKindOfClass:[D self]]) {
// more code
}

As far as I know, this is a bug. The workaround to avoid the table jumping right after tapping a cell is to add:
[self.tableview reloadData];
in your table viewWillDisappear
https://devforums.apple.com/message/1050163#1050163
https://devforums.apple.com/message/1042398#1042398

Related

How to stop Custom cell contain strong label from overwriting the contents?

the Problem is when using strong label type :KILabel to can detect # and #.
after the cell number 10 it keep the value of cell 1 and 11 and so one 2 and 12
it over write the text on each other.
I know the problem from dequeueReusableCellWithIdentifier but how can solve it the rest of feel controls working well just this label.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CommentCell *cell;
CommentsModels * mycomment = [_CommentsModelsArray objectAtIndex:indexPath.row];
if([mycomment.CommentType integerValue] == 2)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"CommentCellImage"];
}else{
cell = [tableView dequeueReusableCellWithIdentifier:#"CommentCell"];
}
// CommentCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CommentCell"];
if (!cell)
{
if([mycomment.CommentType integerValue] == 2)
{
[ tableView registerNib:[UINib nibWithNibName:#"CommentCellImage" bundle:nil]forCellReuseIdentifier:#"CommentCellImage"];
cell = [ tableView dequeueReusableCellWithIdentifier:#"CommentCellImage"];
}else{
[ tableView registerNib:[UINib nibWithNibName:#"CommentCell" bundle:nil]forCellReuseIdentifier:#"CommentCell"];
cell = [ tableView dequeueReusableCellWithIdentifier:#"CommentCell"];
}
}
cell.commentimage.image = nil;
[cell setcell:[_CommentsModelsArray objectAtIndex:indexPath.row]];
cell.commentsViewController = self;
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
return cell;
}
the setcell function
- (void) setcell:(CommentsModels*)comment{
User *user = [[HelpManager sharedHelpManager] applicationUser];
UserId = user.userId;
_generalcomment = comment;
if ( _generalcomment.Comment.length > 0) {
KILabel *label;
label = NULL;
label = nil;
label = [[KILabel alloc] initWithFrame:CGRectMake(76,66, 180, 14)];
label.taggedUsers = comment.TaggedUsers;
NSString *labelText = _generalcomment.Comment;
for (TaggedUser *user in comment.TaggedUsers) {
NSString *replacedText = [NSString stringWithFormat:#"(#%#)%#",user.UserName,user.FullName];
NSString *tagText = [NSString stringWithFormat:#"#%#",user.UserName];
labelText = [labelText stringByReplacingOccurrencesOfString:tagText withString:replacedText];
}
label.text = labelText;
label.tag = 1010;
label.font = [UIFont systemFontOfSize:12];
label.textColor = [UIColor lightGrayColor];
label.automaticLinkDetectionEnabled = YES;
label.linkDetectionTypes = KILinkTypeOptionUserHandle | KILinkTypeOptionHashtag;
label.userHandleLinkTapHandler = ^(KILabel *label, NSString *string, NSRange range) {
TaggedUser *selectedUser = nil;
for (TaggedUser *user in comment.TaggedUsers) {
if ([string containsString:user.UserName] && [string containsString:user.FullName]) {
selectedUser = user ;
break;
}
}
if (selectedUser) {
ProfileViewController *profileViewController = [STORYBOARD instantiateViewControllerWithIdentifier:#"ProfileViewController"];
profileViewController.ProfileUserId = selectedUser.Id;
if ( self.commentsViewController != nil)
{
[self.commentsViewController.navigationController pushViewController:profileViewController animated:YES];
}
else{
[_postandCommentsViewController.navigationController pushViewController:profileViewController animated:YES];
}
}
};
label.hashtagLinkTapHandler = ^(KILabel *label, NSString *string, NSRange range) {
SearchMasterViewController *searchMasterViewController = [STORYBOARD instantiateViewControllerWithIdentifier:#"SearchMasterViewController"];
searchMasterViewController.searchText = string;
if ( self.commentsViewController != nil)
{
[self.commentsViewController.navigationController pushViewController:searchMasterViewController animated:YES];
}
else{
[_postandCommentsViewController.navigationController pushViewController:searchMasterViewController animated:YES];
}
};
label.urlLinkTapHandler = ^(KILabel *label, NSString *string, NSRange range) {
// Open URLs
[self attemptOpenURL:[NSURL URLWithString:string]];
};
[label adjustFrameSize];
[self.contentView addSubview:label];
}
The code has a few problems.
1) register the nibs when you're setting up views, as early as viewDidLoad
// in the view controller that is the table's datasource
// assumes you have an outlet setup in IB to the table view
#property(weak,nonatomic) IBOutlet UITableView *tableView;
// ...
- (void)viewDidLoad {
[super viewDidLoad];
[self.tableView registerNib:[UINib nibWithNibName:#"CommentCellImage" bundle:nil]forCellReuseIdentifier:#"CommentCellImage"];
[self.tableView registerNib:[UINib nibWithNibName:#"CommentCell" bundle:nil]forCellReuseIdentifier:#"CommentCell"];
// plus whatever else you do in viewDidLoad
}
2) next, you can simplify and modernize your cellForRowAtIndex as follows
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
CommentsModels * mycomment = [_CommentsModelsArray objectAtIndex:indexPath.row];
NSInteger type = [mycomment.CommentType intValue];
NSString *identifier = (type == 2)? #"CommentCellImage" : #"CommentCell";
CommentCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath];
cell.commentimage.image = nil;
[cell setcell:[_CommentsModelsArray objectAtIndex:indexPath.row]];
cell.commentsViewController = self;
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
return cell;
}
3) Lastly, the setcell: should factor out the label creation and only create the label conditionally, if the cell doesn't already have one (after the first display of the table, all of the cells will).
// in CommentCell.m
- (UILabel *)theLabel {
KILabel *label = (KILabel *)[cell viewWithTag:1010];
if (!label) { // only create one if its not there
label = [[KILabel alloc] initWithFrame:CGRectMake(76,66, 180, 14)];
label.tag = 1010;
// everything else you do to create the label goes here,
// but NOT anything variable relative to the model, so
// for example, not label.text = anything
[self.contentView addSubview:label];
}
return label;
}
Now setcell: is slightly saner, just getting the (probably already created) label and changing things about only that change for the given model item at the given row.
- (void) setcell:(CommentsModels*)comment {
User *user = [[HelpManager sharedHelpManager] applicationUser];
UserId = user.userId;
_generalcomment = comment;
if ( _generalcomment.Comment.length > 0) {
KILabel *label = [self theLabel];
NSString *labelText = _generalcomment.Comment;
// I didn't try to understand the following code, but it looks
// potentially too slow for configuring a table view cell.
// consider doing this calculation just once and caching the result in the model
for (TaggedUser *user in comment.TaggedUsers) {
NSString *replacedText = [NSString stringWithFormat:#"(#%#)%#",user.UserName,user.FullName];
NSString *tagText = [NSString stringWithFormat:#"#%#",user.UserName];
labelText = [labelText stringByReplacingOccurrencesOfString:tagText withString:replacedText];
[label adjustFrameSize];
}
}
}
because dequeueReusableCell function return old cell that contain old label
so You can remove label before load new item.
- (void) setcell:(CommentsModels*)comment {
[[self.contentView viewWithTag:1010] removeFromSuperview];
//... your cuttom code here
}

Table View Cell Height using Row Height not Auto Layout Height

I have 3 custom Table View Cell's in a UITableView. I have the the height of one cell perfect, but the other two cells I just want them to use AutoLayout for their height.
This is what I have, does anyone have another idea for the else statement?:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
id model = self.Model[indexPath.row];
if ([model isKindOfClass:[D self]]) {
ListTableViewCell *cellOne = [tableView dequeueReusableCellWithIdentifier:#"1Cell" forIndexPath:indexPath];
if (!cellOne) {
cellOne = [[ListTableViewCell alloc] init];
FR *fD = (FR *)model;
NSString *title = [NSString stringWithFormat:#"%#", fD.title];
NSString *dateString = [self timeSincePublished:fD.pubDate];
NSString *description = [self removeHTMLTags:fD.description];
NSString *link = [NSString stringWithFormat:#"%#", fD.link];
cellOne.labelHeadline.text = title;
cellOne.labelDescription.text = description;
cellOne.labelPublished.text = dateString;
}
// Make sure the cell's frame is updated
[cellOne setNeedsLayout];
[cellOne layoutIfNeeded];
CGFloat heightOne = [cellOne.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
return heightOne + 2;
} else {
// This is where I need help for other 2 custom cells to just use AutoLayout height
return tableView.rowHeight;
}
Right now, return tableView.rowHeight is returning the hardcoded height that is set in the storyboard, regardless of how much is actually in the cell.
It should ignore that height and just use AutoLayout.
Do you know a way to do that? Thanks! Will gladly post any extra info if needed-
With auto layout you don't use heightForRowAtIndexPath.
Instead you can use something like this:
self.tableView.estimatedRowHeight = 44.0;
self.tableView.rowHeight = UITableViewAutomaticDimension;

Multi-line UILabel

I've looked over older questions and tried all the suggestions, but still cannot seem to get a multi-line UILabel to work. I have a UITableView and the cell is created by tableView:cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *fieldValue = [self fieldValueAtIndexPath:indexPath];
NSString *fieldName = [self fieldNameAtIndexPath:indexPath];
NSString *title = [[self appDelegate] displayNameForFieldName:fieldName];
Field fieldCode = [[self appDelegate] fieldCodeForFieldName:fieldName];
DetailCell *cell = nil;
NSString *identifier = nil;
BOOL isNotes = [fieldName caseInsensitiveCompare:#"Notes"] == NSOrderedSame;
switch( isNotes ) {
case NO:
{
identifier = #"DetailCell";
cell = (DetailCell*)[tableView dequeueReusableCellWithIdentifier:identifier];
NSInteger rows = [self heightForText:fieldValue andFont:[self textFont] andWidth:cell.value.frame.size.width] / _oneRowSize.height;
cell.value.text = fieldValue;
cell.name.text = [title lowercaseString];
cell.name.numberOfLines = MAX( 1, rows );
cell.value.numberOfLines = cell.name.numberOfLines;
break;
}
case YES:
{
cell = (DetailCell *)[tableView dequeueReusableCellWithIdentifier:#"DetailCellNotes" forIndexPath:indexPath];
// cell = (DetailCell *)[tableView dequeueReusableCellWithIdentifier:#"DetailCellNotes"];
cell.value.text = #"This is a very long line of text which should take up several lines";
cell.name.text = [title lowercaseString];
cell.value.numberOfLines = 5; // No more than 5 lines of text
cell.value.backgroundColor = [UIColor purpleColor];
cell.value.lineBreakMode = NSLineBreakByWordWrapping;
cell.value.frame = CGRectMake(cell.value.frame.origin.x, cell.value.frame.origin.y, 180, 70);
[cell.value sizeThatFits:CGSizeMake(180., 70.)];
break;
}
}
cell.fieldName = fieldName;
return cell;
}
The height in the table view is defined like so
- (CGFloat) tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath
{
NSString *fieldName = [self fieldNameAtIndexPath:indexPath];
CGFloat height = 0.0;
if([fieldName isEqualToString:#"Notes"])
{
height = 70.;
}
else if([fieldName isEqualToString:#"Image"])
{
height = 100.;
};
return height;
}
which makes the cell large enough to hold a 3-line label. However when the cell appears the label is only one line (shown by the background being purple).
The tableview uses prototype cells, and I've also tried to set it to numberOfLines=5 and WordWrapping, but that didn't change the effects either. I've also tried both of the commented out lines (though searches suggest that sizeToFit might actually reset numberOfLines to 1).
I wonder what I've missed. I can't see any other place where the it might be overridden.
Thanks.
You are calling dequeueReusableCellWithIdentifier: to create your cell. This is a mistake, because it means that the cell has not assumed its final size. It is much better to call dequeueReusableCellWithIdentifier:forIndexPath:. This means that the cell will actually have the height that you are giving it in heightForRowAtIndexPath:. You should then be able to set the height of the label successfully.

IOS:Creating a Self-Sizing UITextView Within a UITableViewCell?

I am using stroyboards for my project. My project is based on parsing json datas and displaying it in JSON. While parsing JSON I will receive two different datas. Title and Description
i have to parse this and have to fix in UItextview inside a uitableviewcell i have structured a uitableviewcell like this
TEXTVIEW,TEXTVIEW,LABEL,LABEL,LABEL,LABEL,LABEL;
Now my problem is my text view has to resize according to data, and based on that tableviewcell also has to resize I tried the above code but the view gets collapsing.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"Need_Request";
NeedReqListCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier forIndexPath:indexPath];
type = (NSString *)[array4 objectAtIndex:indexPath.row];
if([type isEqualToString:#"Money Donation"]) {
cell.createdby.text = (NSString *)[array3 objectAtIndex:indexPath.row];
cell.product.text = (NSString *)[array4 objectAtIndex:indexPath.row];
cell.expiration.text = (NSString *)[array5 objectAtIndex:indexPath.row];
cell.titleview.text = (NSString *)[array1 objectAtIndex:indexPath.row];
[cell.descview setHidden:TRUE];
[cell.totalquantity setHidden:TRUE];
[cell.fulfilledquantity setHidden:TRUE];
return cell;
}
else if([type isEqualToString:#"Service"]) {
cell.createdby.text = (NSString *)[array3 objectAtIndex:indexPath.row];
cell.product.text = (NSString *)[array4 objectAtIndex:indexPath.row];
cell.expiration.text = (NSString *)[array5 objectAtIndex:indexPath.row];
cell.titleview.text = (NSString *)[array1 objectAtIndex:indexPath.row];
cell.descview.text = (NSString *)[array2 objectAtIndex:indexPath.row];
[cell.totalquantity setHidden:TRUE];
[cell.fulfilledquantity setHidden:TRUE];
return cell;
}
cell.createdby.text = (NSString *)[array3 objectAtIndex:indexPath.row];
cell.product.text = (NSString *)[array4 objectAtIndex:indexPath.row];
cell.expiration.text = (NSString *)[array5 objectAtIndex:indexPath.row];
cell.totalquantity.text = (NSString *)[array6 objectAtIndex:indexPath.row];
cell.fulfilledquantity.text = (NSString *)[array7 objectAtIndex:indexPath.row];
cell.titleview.text = (NSString *)[array1 objectAtIndex:indexPath.row];
cell.descview.text = (NSString *)[array2 objectAtIndex:indexPath.row];
CGRect bodyFrame = cell.titleview.frame;
bodyFrame.size = cell.titleview.contentSize;
[cell.titleview setFrame:bodyFrame];
CGRect bodyFrame1 = cell.descview.frame;
bodyFrame1.size = cell.descview.contentSize;
[cell.descview setFrame:bodyFrame1];
CGRect bodyFrame2 = cell.createdby.frame;
[cell.createdby setFrame:bodyFrame2];
CGRect bodyFrame3 = cell.product.frame;
[cell.product setFrame:bodyFrame3];
CGRect bodyFrame4 = cell.expiration.frame;
[cell.expiration setFrame:bodyFrame4];
CGRect bodyFrame5 = cell.totalquantity.frame;
[cell.totalquantity setFrame:bodyFrame5];
CGRect bodyFrame6 = cell.fulfilledquantity.frame;
[cell.fulfilledquantity setFrame:bodyFrame6];
return cell;
}
when i tried this code my screen looks like this
Please help me to Solve this issue
Check this link - http://www.springtiger.co.uk/2010/11/28/dynamically-generate-labels-frame-to-match-its-content/
It will explain how to resize UIlabel to fit contents.
One more suggestion would be use a single control and use NSFormatted Text instead of so many labels. (Again it depends on your requirement).
You need to move the labels' frame origin as well so that they are placed below each other. So after you calculate the first textView's size and bounds, set the origin of the second textView to whichever offset from the bottom of the first textView. But that gets complicated when you have to take into account different orientations and device screen sizes...
Why don't you use auto-layout and constraints?

tableView convertPoint: fromView: odd behaviour and workaround

I have a tableView with custom cells. One of the objects in the cell is a textField.
The tableViewController is the textFieldDelegate.
The datasource for the table is an array of objects.
When the user tap on the textField, the tableViewController implements textField delegates methods controlling this way the data entry.
To use the data entered by user, the tableViewController implements the following:
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
CGPoint point = [textField center];
point = [self.tableView convertPoint:point fromView:textField];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:point];
...
...
return YES
}
I spent two hours trying to figure out why indexPath.row was always wrong, it was always row+1 of what it suppose to be.
Solution: In the storyboard I move the textField to the upper portion of the cell.
Has anyone see something like this before?
Thanks.
-[UIView center] returns the center of the view's frame, which is in the view's superview's coordinate system. But -[UIView convertPoint:fromView:] expects to be given a point in the "from" view's coordinate system.
Either give it the same point, and tell it to convert from the correct view:
CGPoint point = [textField center];
point = [self.tableView convertPoint:point fromView:textField.superview];
Or give it a point in the view's coordinate system, and tell it to convert from the view:
CGRect textFieldBounds = textField.bounds;
CGPoint point = CGPointMake(CGRectGetMidX(textFieldBounds), CGRectGetMidY(textFieldBounds));
point = [self.tableView convertPoint:point fromView:textField];
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *text = [array_loaddata objectAtIndex:indexPath.row] ;
UIFont *font = [UIFont systemFontOfSize:10];
CGSize size = [(text ? text : #"") sizeWithFont:font constrainedToSize:CGSizeMake(220, 9999) lineBreakMode:NSLineBreakByWordWrapping];
int count = size.height + 0;
return count;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [array_loaddata count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier =[NSString stringWithFormat:#"Cell%d",indexPath.row] ;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
NSString *text = [array_loaddata objectAtIndex:indexPath.row] ;
UIFont *font = [UIFont systemFontOfSize:10];
CGSize size = [(text ? text : #"") sizeWithFont:font constrainedToSize:CGSizeMake(220, 9999) lineBreakMode:NSLineBreakByWordWrapping];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(46, 0, size.width, size.height)];
label.numberOfLines = 0;
label.textColor = [UIColor grayColor];
label.lineBreakMode = NSLineBreakByWordWrapping;
label.text = (text ? text : #"");
label.font = font;
label.backgroundColor = [UIColor clearColor];
[cell.contentView addSubview:label];
[label release];
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
link==http://mobile.tutsplus.com/tutorials/iphone/iphone-json-twitter-api/
/*
NSString *appurl =[NSString stringWithFormat:#"xx"];
appurl = [appurl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:[NSURL URLWithString:appurl]];
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse: nil error: nil ];
NSString *returnString = [[NSString alloc] initWithData:returnData encoding: NSUTF8StringEncoding];
*/
}

Resources