How to set different height for different rows of UITableView - ios

how can i set different height for different rows of custom ui table view cell in ios?
I am trying to change the height depending upon the how much lines there are in my uitextview which is inside my custom uitableview cell.
I tried setting height like this inside my heightForRowAtIndexPath method but it crashes:
PostStreamCell *cell = [tableView cellForRowAtIndexPath:indexPath];
int lines = cell.txtViewMessage.contentSize.height / cell.txtViewMessage.font.lineHeight;
if(lines < 4)
{
return 100;
}
else if(lines == 4)
{
return 100;
}
else{
return 220;
}

You can't use cellForRowAtIndexPath in heightForRowAtIndexPath because the cell does not exist. You must retrieve the text by another way without use the cell.

Try by using the text boundingRectWithSize.. for calculating the size for cell itself .
Something like this :
NSString *text = yourTextView.text;
CGSize size;
NSDictionary *attributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
[UIFont fontWithName:#"Helvetica Neue" size:19], NSFontAttributeName,
nil];
CGRect fontSizeFor7 = [text boundingRectWithSize:CGSizeMake(525, 500)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:attributesDictionary
context:nil];
size = fontSizeFor7.size;
return size.height +40;

I suggest you to count
int lines
in
viewDidLoad
method using length of your text field. Then store it in some array and use it values in your
heightForRowAtIndexPath
method. It should look like this
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (myLinesArray[indexPath.row] =< 4)
{
return 100;
}
else return 220;
}

You are setting the height correctly--however, you probably shouldn't retrieve a cell within heightForRowAtIndexPath by calling cellForRowAtIndexPath, that is unless your cells are already statically created. A bare-bones implementation of heightForRowAtIndexPath (below) doesn't crash, so the problem probably lies elsewhere in your view controller implementation, or elsewhere.
Also noticed that you are dividing by a dynamic value to get the height. Check your PostStreamCell--if the cell object, txtViewMessage, or its font property is nil, then you will be dividing by 0, and that could be causing the crash.
//Very simple implementation to demo changes in height
- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row % 2) {
return 60;
} else {
return 44;
}
}

Related

UITextView sizeThatFits returns different size than boundingRectWithSize

Need the required height of UITextView. sizeThatFits returns bigger, but the correct height than boundingRectWithSize. Why difference exist?
At two places I need to know the height. In cellForRowAtIndexPath and in heightForRowAtIndexPath.
I do not think it is efficient to create always a UITextView in heightForRowAtIndexPath just to know what height is required.
What workaround do you know to calculate height of a UITextView in heightForRowAtIndexPath?
I met similar problem last month for UITableView, and I use boundingRectWithSize to calculate the size, it is actually correct. I then put it into UITextView.
Some mistakes I made:
I forget to set the same font size when calculating and for UITextView
UITextView has margins, I will manually add it in heightForRowAtIndexPath and set textContainerInset to the same one.
Hope it helps you.
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
NSInteger section = indexPath.section;
NSUInteger axisIndex = section - 2;
yAxis *yAxisObj = self.yAxisInfoArray[axisIndex];
boundingRect = [yAxisObj.yAxisDescription boundingRectWithSize:CGSizeMake(self.descriptionViewWidth, CGFLOAT_MAX)
options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading
attributes:#{NSFontAttributeName:self.contentFont}
context:nil];
return boundingRect.size.height + TEXT_TOP_MARGIN + TEXT_BOTTOM_MARGIN;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellId = #"ChartDescriptionCell";
ChartDescriptionCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
if (!cell) {
cell = [[ChartDescriptionCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId];
cell.textView.bounces = NO;
cell.textView.showsHorizontalScrollIndicator = NO;
cell.textView.showsVerticalScrollIndicator = NO;
cell.textView.font = self.contentFont;
cell.textView.textColor = [UIColor colorWithHex:#"#333333"];
cell.textView.textContainerInset = UIEdgeInsetsMake(TEXT_TOP_MARGIN, -5, TEXT_BOTTOM_MARGIN, -5);
}
NSInteger section = indexPath.section;
NSUInteger axisIndex = section - 2;
yAxis *yAxisObj = self.yAxisInfoArray[axisIndex];
cell.textView.text = yAxisObj.yAxisDescription;
}
return cell;
}
boundingRectWithSize returns size for text, so you should manually provide your font.
sizeThatFits returns size of UITextView with this text inside
If you are pointing to iOS 8 and above you can use Dynamic cell height which is very easy. In case of iOS 7 you need some workaround.
Tutorial: http://www.raywenderlich.com/87975/dynamic-table-view-cell-height-ios-8-swift
Related question with nice answer: Using Auto Layout in UITableView for dynamic cell layouts & variable row heights

How to change each UITableViewCell height dynamically?

I'm working on application where i show user comment in UILable and UILable have sizetofit property. i want to change cell height according to UILable height.
My Question is how i change cell height for example first cell height may be 50, second Cell height may be 100 and so on.
For dynamic height of UITableViewCell you have to do below things
Fulfill all constraint requirement in UITableViewCell
Tell your TableView to dynamically layout Height of every Cell with below code
- (void)viewDidLoad {
[super viewDidLoad];
// two magic lines
tableView.estimatedRowHeight = 89
tableView.rowHeight = UITableView.automaticDimension
}
With just two lines of code, you instruct the table view to calculate the cell’s size matching its content and render it dynamically. This self sizing cell feature should save you tons of code and time. You’re gonna love it.
Hope this helps you by tableview methods:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewAutomaticDimension;
}
You can use this method for increase UITableViewCell height dynamically (No AutoLayout)
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
NSMutableAttributedString *strName = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:#"%#",strItemName]];
[strName addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:16] range:NSMakeRange(0, strItemName.length)];
CGSize sizeItemName = CGRectIntegral([strName boundingRectWithSize:CGSizeMake(130, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin context:nil]).size;
int padding = 5;
//your default cell height for ex 55
if (sizeItemName.height < 55)
{
sizeItemName.height = 55;
}
return sizeItemName.height + padding;
}
In your heightForRowAtIndexPath, calculate the dynamic height based on the related cell data.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary *data = [self.dataSource objectAtIndex:indexPath.row];
return [MyTableViewCell heightForData:data];
}
Then in your MyTabLeViewCell, write a function as below, let us say the data has the "content" which is the fact for dynamic height. And your tableViewCell defined a UILabel called contentLabel with CONTENT_LABEL_WIDTH
+(CGFloat) heightForData : (NSDictionary *)data{
self.contentLabel.text = [data objectForKey:#"content"];
CGSize contentLabelSize = [self.contentLabel sizeThatFits:CGSizeMake(CONTENT_LABEL_WIDTH, CGFLOAT_MAX)];
return contentLabelSize.height;
//If you want to have a minimum cell height no matter how small your content is, you can use below fmaxf with a pre-defined CELL_MIN_HEIGHT value.
// return fmaxf(CELL_MIN_HEIGHT, height);
}

Dynamically set size of UITableViewCell with UITextView

I have UITextViews in UITableViewCells. What I want to do is make the cell fit the textView If the cell contains a textView. I can make a if statement for every cell and return the textView's size, (I have more than 1 cell with a textView) as I started in the code below, but I'm sure there is another way of doing this.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 1 && indexPath.row == 0) {
return myTextview.frame.size.height + 40;
}
return 44;
}
I'm a beginner, so please don't be too harsh.
first decide if the cell is consisting of UITextView or not.if yes according to textview size give the row height.(But make sure your adding the textview to the content view of cell)
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
for (UIView *tempView in [[tableView cellForRowAtIndexPath:indexPath].contentView subviews])
{
if (tempView isKindOfClass:[UITextView Class])
{
return tempView.frame.size.height + 40;
//(or) for dynamic cell height
//CGSize Size= [tempView.text boundingRectWithSize:CGSizeMake(200, 1000000)
options:NSLineBreakByWordWrapping |
NSStringDrawingUsesLineFragmentOrigin
attributes:#{
NSFontAttributeName :[UIFont fontWithName:#"Helvetica" size:12]
}
context:nil].size;
//return Size.height;
}
}
return 44;
}
you can always do it in cell class,declare a method and name it, for example ,
layoutCellByString:(NSString *) stringContent, measure and adjust cell height
and declare another method call getCellHeight in cell class, and return self.frame.size.height;
and in heightForRowAtIndexPath, you can do this:
YourCellClassName *cell = (YourCellClassName *)[self tableView:self.tableView cellForRowAtIndexPath:indexPath];
return [cell getCellHeight];
you should call layoutCellByString in cellForRowAtIndexPath in order to make this work
ps: apologize for the pool english by the way.

Cells are overlapping

I have a problem in my iPhone app. Sometimes, some cells of the UITableView of my home screen are overlapping and does not appear correctly.
Here is how sometimes (very rarely) my app is appearing :
I created two types of custom UITableViewCell, with a xib file to design them.
Do you have any idea on what can cause this ? Is this a bug of iOS, because I already noticed this kind of bug in an other app.
Thanks for your help.
UPDATE : here is my tableView:heightForRowAtIndexPath: method.
I'm returning the correct height depending on the two types of cells.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
Article *article = [self.articles objectAtIndex:[indexPath row]];
if (article.isFeatured) {
return 110;
} else {
return 75;
}
}
Unless you are overriding -tableView:heightForRowAtIndexPath: with the height of your cell, all your cells will have the standard height of 44 points.
In your TableView Delegate you need to have
- (CGFloat)tableView:(UITableView *) tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
CGFloat cellHeight = 44.0;
//Calculate your cell height using indexPath and save it in cellHeight;
// Then
return cellHeight;
}
Try this
NSString *CellIdentifier = [NSString stringWithFormat:#"Cell %d",indexPath.row];
UITableViewCell *cell=[self.tableView cellForRowAtIndexPath:indexPath];
if (cell == nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 30.0f;
}
I think you to calculate your cell height dynamically according to you content.
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
CGSize constrainedSize = CGSizeMake(self.view.frame.size.width - 30, FLT_MAX);
NSDictionary *attributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
[UIFont fontWithName:#"HelveticaNeue" size:14], NSFontAttributeName,
nil];
CGRect requiredHeight = [self.articles objectAtIndex:[indexPath row] boundingRectWithSize:constrainedSize
options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
attributes:attributesDictionary
context:nil];
return requiredHeight.size.height + 20;
}
For those who arrive here, I got the exact same issue in iOS 11 and it also happened very rarely. It turns out that I was doing some animated edits in my table view but I had 2 problems: sometimes these updates happened when the controller where this table view was placed was not on screen, so the table view had no window; other times the view controller was on screen but the animation was inside a UIView.performWithoutAnimation block (due to a bad refactor), like this:
UIView.performWithoutAnimation {
tableView.beginUpdates()
// a couple of calls to tableView.insertRows(at:with:)
// and tableView.deleteRows(at:with:)
tableView.endUpdates()
}
In my case, I removed the UIView.performWithoutAnimation and enabled the animations again, but if you need to keep the table updates without animation, I suggest that you remove the calls to tableView.beginUpdates() and tableView.endUpdates() and do the updates with animation .none, or just call tableView.reloadData().
I also did a check to see if the view controller containing this table view has the view loaded and its view.window != nil, and if not I just do a tableView.reloadData() Instead of animating the edits. Probably checking if tableView.window != nil will do the same.
I hope this helps someone :)

Need to access my UITableViewCell class in UITableView's heightForRowAtIndexPath:

I need to set UITableViewCell height based on my UITextView height, but when I access cell sublcass using: CommentTableViewCell *cell = (CommentTableViewCell *)[tableView cellForRowAtIndexPath:indexPath]; in heightForRowAtIndexPath:, app crashes.
What's wrong? Isn't this the right way to access my custom cell class?
From my experience, heightForRowAtIndexPath is triggered automatically before it displays the cell. So you need to know the height of the cell before it is displayed. You can not do this in heightForRowAtIndexPath at is seems that you think that you can change it be looking at cell's text's height during heightForRowAtIndexPath.
What you need to do is create an array and store the height. You can now then use that array and extract the number inside heightForRowAtIndexPath.
Here's an example:
- (void) calculateHeight {
UILabel *tempTitle = [[UILabel alloc] init];
tempTitle.font = [UIFont fontWithName:#"your font" size:#"size"];
tempTitle.lineBreakMode = NSLineBreakByWordWrapping;
for (int i = 0; i < [yourListOfData count]; i++) {
NSString *yourText = [yourListOfData objectAtIndex:i];
CGSize textSize = [yourText
sizeWithFont:#"size"
constrainedToSize:CGSizeMake(0, "maxsize of your label that you want")
lineBreakMode:NSLineBreakByWordWrapping];
[listOfHeightPerItem addObject:[NSNumber numberWithFloat:(textSize.height + 20)]];
//+20 for padding
}
}
and then in your heightForRowAtIndexPath:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
CGFloat tempHeight = [(NSNumber *)[listOfHeightPerItem objectAtIndex:indexPath.row] floatValue];
return tempHeight;
}
Please note that this isn't the most optimal way but it works... especially when your deadline was yesterday ;)
If the UITextView height depends on some string length unknown until run time, then you should follow MVC architecture and determine the height from that string as defined in some model object. You can use NSString sizeWithFont or sizeWithAttributes methods to get the text size.

Resources