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.
Related
I have label in a cell, when I click on a cell I want to cell increases as much as the size of label. Currently my code resizes the cell to 240.
My label:
UILabel *cellLabel3 = (UILabel *)[cell viewWithTag:5];
[cellLabel3 setText:[Data objectAtIndex:self.expandedIndexPath.row]];
Code for cell height:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([indexPath compare:self.expandedIndexPath] == NSOrderedSame) {
return 240;
}
return 90.0;
}
Try this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
self.expandedIndexPath = indexPath;
[self.tableView reloadData];
}
This Question has answer already But still posting answer,
Calculate Height of Text from method
CGSize maximumSize = CGSizeMake(kLabelWidth, CGFLOAT_MAX);
CGSize size = [text sizeWithFont:font
constrainedToSize:maximumLabelSize
lineBreakMode:UILineBreakModeWordWrap];
And replace kLabelWidth with label width & font with your label font
and return size.height from heightForRowAtIndexPath.
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;
}
}
I have a custom table view & cell where a cell is expanded when selected. It is now functioning properly and accordingly. However, When I select cells to expand them, it takes about half a second to respond. The code below is located in the didSelectRowAtIndexPath. My hypothesis is that between beginUpdates and endUpdates, there are too many things going on to increase the height of the original cell and then updating the whole table view. Is there another way I can better implement this?
**[_tableView beginUpdates];**
ReviewTestTableCell *reviewCell1 = (ReviewTestTableCell *)[tableView cellForRowAtIndexPath:indexPath];
CGRect rect = CGRectMake(reviewCell1.review.width, 900, reviewCell1.review.width, 900);
CGRect textRectb = [reviewCell1.review textRectForBounds:rect limitedToNumberOfLines:1000];
float labelHeight = textRectb.size.height;
reviewCell1.review.height = labelHeight;
expandHeight = labelHeight + 75 ;
if ([[userdefaults objectForKey:#"merchantType"] isEqual:#"T"])
{reviewCell1.height = labelHeight + 50;
reviewCell1.bottomRatingView.height = reviewCell1.bottomRatingView.height - 20;
}
else
{
reviewCell1.height = labelHeight + 75;}
reviewCell1.bottomRatingView.hidden = NO;
reviewCell1.bottomRatingView.top = reviewCell1.review.bottom;
**[_tableView endUpdates];**
[_isExpandList replaceObjectAtIndex:indexPath.row withObject:#1];
}
EDIT/ADD:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell3 = [self tableView:tableView cellForRowAtIndexPath:indexPath];
if ([_isExpandList[indexPath.row] isEqual: #1] && [[_dataList objectAtIndex:indexPath.row] valueForKey:#"Item1Score"] != nil) {
return cell3.height + 3 + 65;
}
else if ([_isExpandList[indexPath.row] isEqual: #0])
{
return cell3.height +5;
}
else return cell3.height +3;
}
You should not go through that elaborate dance of trying to manually expand the cell. You should certainly not manually call willDisplayCell.
Using the method described in the answer to this question, you should have a property or something to keep track of which cell was selected and make your heightForRowAtIndexPath: method adjust for that particular indexPath, then just call
[tableView beginUpdates];
[tableView endUpdates];
Which will call heightForRowAtIndexPath for every cell, which your method will give a larger height for when it matches the selected row. The tableView will smoothly adjust the height of your cell.
Something similar to:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([self.selectedIndexPath isEqual:indexPath]) {
return 80.0f;
}
return tableView.rowHeight;
}
I have a UITableview with multiple reusable TableViewCells.
In one cell I have a UITextView, that resizes itself to fit its content. Now I "just" have to resize the contentView of the TableViewCell, so I can read the while text. I already tried:
cell2.contentView.bounds.size.height = cell2.discriptionTextView.bounds.size.height;
Or:
cell2.contentView.frame = CGRectMake(0, cell2.discriptionTextView.bounds.origin.y,
cell2.discriptionTextView.bounds.size.width,
cell2.discriptionTextView.bounds.size.height);
In the method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath
*)indexPath {}
But it won't work.
Does anyone know how to do this?
New code:
#implementation AppDetail
CGFloat height;
…
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{…
cell2.TextView.text = self.text;
[cell2.TextView sizeToFit];
height = CGRectGetHeight(cell2.TextView.bounds);
…
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == 0) {
return 143;
}
if (indexPath.row == 1) {
return height;
}
return 0;
}
You can only resize a UITableViewCell in tableView:heightForRowAtIndexPath: delegate method.
You have to estimate what the size of the text will be when that method is called for every row when the tableView is loaded.
This is what I did to solve the problem.
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString * yourText = self.myArrayWithTextInIt[indexPath.row]; // or however you are getting the text
return additionalSpaceNeeded + [self heightForText:yourText];
}
-(CGFloat)heightForText:(NSString *)text
{
NSInteger MAX_HEIGHT = 2000;
UITextView * textView = [[UITextView alloc] initWithFrame: CGRectMake(0, 0, WIDTH_OF_TEXTVIEW, MAX_HEIGHT)];
textView.text = text;
textView.font = // your font
[textView sizeToFit];
return textView.frame.size.height;
}
EDIT
While I used this solution for a while, I found a more optimal one that I would recommend using as it doesn't require allocating an entire textView in order to work, and can handle text greater than 2000.
-(CGFloat)heightForTextViewRectWithWidth:(CGFloat)width andText:(NSString *)text
{
UIFont * font = [UIFont systemFontOfSize:12.0f];
// this returns us the size of the text for a rect but assumes 0, 0 origin
CGSize size = [text sizeWithAttributes:#{NSFontAttributeName: font}];
// so we calculate the area
CGFloat area = size.height * size.width;
CGFloat buffer = whateverExtraBufferYouNeed.0f;
// and then return the new height which is the area divided by the width
// Basically area = h * w
// area / width = h
// for w we use the width of the actual text view
return floor(area/width) + buffer;
}
As #Rob Norback said, There is something called UITableViewAutomaticDimension.
For Swift, The easiest way to resize content from UITableViewCell on the fly is to just add this.
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
override func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
Here's an updated version for iOS 7+ that is cleaner (no extra method)
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
UIFont * font = [UIFont systemFontOfSize:15.0f];
NSString *text = [getYourTextArray objectAtIndex:indexPath.row];
CGFloat height = [text boundingRectWithSize:CGSizeMake(self.tableView.frame.size.width, maxHeight) options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading) attributes:#{NSFontAttributeName: font} context:nil].size.height;
return height + additionalHeightBuffer;
}
You need you implement heightForRowAtIndexPath.
Say that the data that is to be displayed in the textView is stored in a NSArray.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
CGFloat cellheight = 30; //assuming that your TextView's origin.y is 30 and TextView is the last UI element in your cell
NSString *text = (NSString *)[textArray objectAtIndex:indexpath.row];
UIFont *font = [UIFont systemFontOfSize:14];// The font should be the same as that of your textView
CGSize constraintSize = CGSizeMake(maxWidth, CGFLOAT_MAX);// maxWidth = max width for the textView
CGSize size = [text sizeWithFont:font constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];
cellHeight += size.height; //you can also add a cell padding if you want some space below textView
}
I favor this solution of Jure
First, set constraints of textview to be pinned with its superview (cell's contentView in this case).
Disable textView.scrollEnabled
Set
table.rowHeight = UITableViewAutomaticDimension;
tableView.estimatedRowHeight = 44;
If finally, your code not works, then use this instead
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 44;
}
Implement UITextViewDelegate like this:
- (void)textViewDidChange:(UITextView *)textView {
CGPoint currentOffset = self.tableView.contentOffset;
[UIView setAnimationsEnabled:NO];
[self.tableView beginUpdates];
[self.tableView endUpdates];
[UIView setAnimationsEnabled:YES];
[self.tableView setContentOffset:currentOffset animated:NO];
}
This thread has been quite a while, but in iOS 8 UITableViewAutomaticDimension was introduced. You have to set constraints from the top to the bottom of the cell like a scroll view to make this work. But after that, just add the following code to viewDidLoad():
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 122.0
Make sure your estimated height is as close as possible to the real thing otherwise you'll get some buggy scrolling.
Adding these two methods to the ViewController with UITableViewAutomaticDimension should do the trick. It has worked for me when embedding a UITextView inside of a UITableViewCell with variable length text.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewAutomaticDimension;
}
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewAutomaticDimension;
}
In case of UILabel subview in the UITableViewCell, I accomplished auto resize of the label just by setting the label's constraints (using storyboard, Xcode 8.3.2).
This is working since apparently the label's and the cell's default behavior is sizeToFit. Same should work for UITextView as well.
I have a tableview representing a feed, with three different custom UITableView cells. One (the top one) is solid and should always be there, but the cells underneith that one is either a product or an event cell (loaded from DB). The thing is that the Eventcells have a textview and an imageview that can varie in height, so to view these correctly I calculate the correct height for them and then set the height in heightForRowAtIndexPath. I need to update the cell with its new height somehow, so I do an tableview begin/end update. However when I do this for every cell each time its loaded into view, all the cells start bouncing around and change content when I scroll the tableview.
Here is my CellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0) {
return [self loadJobInfoCell:indexPath];
} else if (indexPath.section == 1) {
if ([[jobDetailsArray objectAtIndex:indexPath.row] isKindOfClass:[JobProduct class]]) {
return [self loadProductCell:indexPath];
} else if ([[jobDetailsArray objectAtIndex:indexPath.row] isKindOfClass:[JobEvent class]]) {
static NSString *CellIdentifier = #"EventCell";
EventCell *cell = [tableViewRef dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = [[EventCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
JobEvent *currentEvent = [jobDetailsArray objectAtIndex:indexPath.row];
// setting labels and stuff here
// Is there an image to this event?
if (![currentEvent.EventPicture isEqual:[NSNull null]]) {
[[cell largeImage] setImage:currentEvent.EventPicture];
[[cell largeImageHeightConstraint] setConstant:currentEvent.EventPicture.size.height];
NSNumber *height = [NSNumber numberWithFloat:currentEvent.EventPicture.size.height];
[largeImagesDictionary setObject:height forKey:[NSString stringWithFormat:#"%d", indexPath.row]];
} else {
[[cell largeImageHeightConstraint] setConstant:0.f];
}
// set correct height for the textview
NSDictionary *attributes = #{NSFontAttributeName: [UIFont systemFontOfSize:14]};
CGRect paragraphRect = [cell.tvText.text boundingRectWithSize:CGSizeMake(204.f, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading attributes:attributes context:nil];
[[cell tvTextHeightConstraint] setConstant:paragraphRect.size.height+16.f];
NSNumber *height = [NSNumber numberWithFloat:[[cell tvTextHeightConstraint] constant]];
[eventTextHeightDictionary setObject:height forKey:[NSString stringWithFormat:#"%d", indexPath.row]];
[tableViewRef beginUpdates];
[tableViewRef endUpdates];
return cell;
}
}
return nil;
Without the begin/endupdates it works fine, though the cells are not the correct height and get cut of. Can I somehow update the height without reloading the table, or is there a better solution to the whole situation? Ive tried keeping track of which cells have gotten their update but that doesn't work, it still messes up the order, height and content. I've tried every combination of solutions I could possibly think of, but being a novice iOS developer im not even sure im taking the correct approach to this problem.
Thanks very much in advance.
EDIT:
Man, Im stupid.. I've sat and calculated heights in cellforrowatindex insted of in heightforrowatindex and passed the data inbetween with nsdictionaries. I solved this with autolayout and pre-calculating the height of the data in heightforrowatindex.
I'm not exactly sure of your setup, but the way I've done this, is to set up the constraints in IB so that the image view and text view will expand automatically as the cell does. By doing it this way, I don't have to do any size changes for the image view or text view in code, just the cell size. My cell setup looks like this:
The image view is centered in the x direction and has a constraint to the top of the cell and one from the bottom to the top of the text view. The text view has constraints to the sides and to the bottom of the cell. I put a dummy image in the image view, and selected "Size To Fit Content" from the Editor menu -- this cause the height and width constraints for the image view to be deleted.
In code, I calculate the sizes for the image view and text view, then return the sum of their heights (plus a fudge factor) in heightForRowAtIndexPath. Here is the code for a sample app:
- (void)viewDidLoad {
[super viewDidLoad];
self.theData = #[#{#"text":#"jkkjhkj kh k jk h hkj hjkhkjh hjkh jk hhkjhjkh jkh hkj hkjh hkjhjkhhkk jk jkh jkhkhkjhjhkjhkjhkkjhjjhk kjhkjh jkh hk h kj h jkh jkh kjh kh hjkhk jhjk", #"Pic":#"pic1.jpg"},#{#"text":#"fjhg lfkgh gjk gjk glkjfhgjkhgjkgh sjkghsjkgsjgjgk jgk hg hdgjlhjhjgjg fgjklfg fghjgk gjlkg hjgh jg jlkgljsdkggjlglgjdlkg hgjlgjfkghjg ljhfg jlskfdg hjgjlkgjlkdf gjfghjlkfgljkgjlkdgjdfghjdgjglhjkg hljkg ljkgljkfgljkgljksdgljkfgjlfg ljfglldkfjgh ljkgjlkf dgfghslfjdgklfjgljfdfgl", #"Pic":#"pic2.tiff"},#{#"text":#"jdkh lj flfh ljs fajlh ljds f", #"Pic":#"pic3.tiff"}];
[self.tableView reloadData];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.theData.count;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
CGSize textViewSize = [self.theData[indexPath.row][#"text"] sizeWithFont:[UIFont systemFontOfSize:14] constrainedToSize:CGSizeMake(280.f, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
UIImage *pic = [UIImage imageNamed:self.theData[indexPath.row][#"Pic"]];
CGSize imageViewSize = pic.size;
return textViewSize.height + imageViewSize.height + 40;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
RDCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.tv.text = self.theData[indexPath.row][#"text"];
cell.iv.image = [UIImage imageNamed:self.theData[indexPath.row][#"Pic"]];
return cell;
}