Auto Size cell based on UITextView - ios

I have a UITextView in a UITableViewCell in the storyboard. I then added a constraint on all 4 sides of the UITextView.
In the code below I tried making the textView dynamically change as the user enters text. I'm pretty sure that worked successfully. But the problem is the cell is not. Bellow is the code I tried, without success.
-(void)viewDidLoad
{
tableView.rowHeight = UITableViewAutomaticDimension;
tableView.estimatedRowHeight = 44;
}
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
if (textView == myTextView)
{
[self textViewFitToContent:myTextView];
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:#[[NSIndexPath indexPathForItem:1 inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
}
return YES;
}
- (void)textViewFitToContent:(UITextView *)textView
{
CGFloat fixedWidth = textView.frame.size.width;
CGSize newSize = [textView sizeThatFits:CGSizeMake(fixedWidth, MAXFLOAT)];
CGRect newFrame = textView.frame;
newFrame.size = CGSizeMake(fmaxf(newSize.width, fixedWidth), newSize.height);
textView.frame = newFrame;
textView.scrollEnabled = NO;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return myTextView.frame.size.height + 40;
}
I'm a beginner so please don't be too harsh on me.
Thanks

Your code is fine, flawless infact and quite well done. Without seeing your declared variables, I believe the reason that the cell isn't resizing is because you're heightForRowAtIndexPath method is returning the height of the wrong UITextView. Instead of txtSymptoms which isn't used anywhere else in the resizing code, you should be using myTextView instead, which, when the user edits the text of, will trigger the tableView to reload.

This snippet of yours:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return myTextView.frame.size.height + 40;
}
From the rest of your code, myTextView seems to be a special text view that you are adding text to and resizing, but this method uses that larger height for sizing, which is why all of your cells grow taller.

In the storyboard, select your text view and in the size inspector look for the content hugging priority option.
Content hugging priority can range from 0 to 1000.
Keep the content hugging priority of your text view (for vertical section especially) higher than the content hugging priority of the content view of the cell in which the text view resides.

Related

Unexpected behavior of systemLayoutSizeFittingSize: and size classes

I've got some strange problem related to dynamically sized cells, auto layout and size classes. My test project is completely based on Ray's tutorial. It seems that the only difference is UILabels's font sizes for size classes.
The height calculation is wrong when I set another font size for label in some size class. I've made screenshot to illustrate it.
Wwith wrong cell's height calculations:
With correct cell's height calculations:
In addition, I've pushed test project to the github.
EDITED:
ViewController.m
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return [self heightForCellAtIndexPath:indexPath];
}
- (CGFloat)heightForCellAtIndexPath:(NSIndexPath *)indexPath {
static CustomTableViewCell *sizingCell = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sizingCell = [self.tableView dequeueReusableCellWithIdentifier:kBasicCell];
});
[self configurateCell:sizingCell atIndexPath:indexPath];
return [self calculateHeightForCell:sizingCell];
}
- (CGFloat)calculateHeightForCell:(CustomTableViewCell *)cell {
cell.bounds = CGRectMake(0.0f, 0.0f, CGRectGetWidth(self.tableView.frame), CGRectGetHeight(cell.bounds));
[cell setNeedsLayout];
[cell layoutIfNeeded];
CGSize size = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
return size.height +1.0f;
}
CustomLabel.m
- (void)setBounds:(CGRect)bounds {
[super setBounds:bounds];
if (self.numberOfLines == 0 && bounds.size.width != self.preferredMaxLayoutWidth) {
self.preferredMaxLayoutWidth = self.bounds.size.width;
[self setNeedsUpdateConstraints];
}
Since you're already using Auto Layout, I'd recommend also taking advantage of self-sizing cells. You won't need any row height calculation, as iOS can adjust the cell's height automatically, based on the UILabel height.
Add Auto Layout constraints to your contentView's UILabel. This will cause the cell to adjust its contentView height based on the label's contents.
Enable row height estimation.
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 44.0;
For more information, see the detailed walkthrough by smileyborg in his answer to Using Auto Layout in UITableView for dynamic cell layouts & variable row heights.

UILabel's inside UITableViewCell not resizing when orientation changes

I'm populating my UITableView with cells that contain two UILabel's: one of them being the title and the other one being the content. I'm calculating their sizes in heightForRowAtIndexPath: and everything seems cool until I change the orientation. When I change the orientation, the size of each label doesn't seem to change. For example if I'm changing from portrait to landscape, the expected behaviour is to see label's with smaller height (assuming it's a multi-line label). However, the labels' heights remain the same and I get an ugly, disoriented view. The code I've written for this is as follows:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
CGFloat tableWidth = [tableView bounds].size.width;
ListItem* glossaryItem;
if ([tableView isEqual:self.searchDisplayController.searchResultsTableView])
{
glossaryItem =(ListItem*)[self.searchResults objectAtIndex:indexPath.row];
}
else
{
glossaryItem =(ListItem*)[self.glossary objectAtIndex:indexPath.row];
}
NSString* name = [NSString stringWithFormat:#"<p><b>%#</b> :</p>", glossaryItem.name];
NSString* content = glossaryItem.details[0];
NSAttributedString* nameWithStyle = [HTMLParser parseText:name withFontSize:16 withFontType:#"Light"];
NSAttributedString* contentWithStyle = [HTMLParser parseText:content withFontSize:16 withFontType:#"Light"];
CGRect nameRect = [nameWithStyle boundingRectWithSize:CGSizeMake(screenWidth - 40, CGFLOAT_MAX) options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading) context:NULL];
CGRect contentRect = [contentWithStyle boundingRectWithSize:CGSizeMake(screenWidth - 40, CGFLOAT_MAX) options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading) context:NULL];
return nameRect.size.height + contentRect.size.height + 33;
}
HTMLParser is a class I wrote to parse text's in HTML format into attributed strings. I'm guessing the problem here is the label's sizes are not recalculated after orientation change. If I add the following code, everything looks fine but this takes too much time for tables with a lot of cells.
- (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation{
[self.tableView reloadData];
}
How can I work around this? I can provide the constraints of my labels if needed.
Setup autoLayout constraints
or, continue to call the reloadData the way you are doing on didRotate...
but size the labels in cellForRow... like below
Set the height for row only in heightForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//Some identifier and recycling stuff
if (UIInterfaceOrientationIsPortrait(self.interfaceOrientation)) {
//Make labels smaller
}
else {
//Make them longer
}
// save the calculated height for the label
//and size your tableviewrow height accordingly in heightForRowAtIndexPath
}

Resize text view and table view cell dynamically in static table view

I have a static table view that I am using as a sot of data entry for my app. One of those cells has a UITextView in it, which needs to grow and shrink dynamically as the user types, as well as the cell growing/shrinking logically with it. I read a bunch of posts on this but I think I am getting thrown because I am using a STATIC table view.
Here is my resizing attempt (its pretty much a total fail):
- (void)textViewDidChange:(UITextView *)textView
{
self.numberOfLines = (textView.contentSize.height / textView.font.lineHeight) - 1;
float height = 44.0;
height += (textView.font.lineHeight * (self.numberOfLines - 1));
CGRect textViewFrame = [textView frame];
textViewFrame.size.height = height - 10.0; //The 10 value is to retrieve the same height padding I inputed earlier when I initialized the UITextView
[textView setFrame:textViewFrame];
[self.tableView beginUpdates];
[self.tableView endUpdates];
[self.messageTextView setContentInset:UIEdgeInsetsZero];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
float height = 44.0;
if (self.messageTextView) {
height += (self.messageTextView.font.lineHeight * (self.numberOfLines - 1));
}
return height;
}
I'll take any tips! Thanks.
You don't have to do anything just go through this code:-
There is a new function to replace sizeWithFont, which is boundingRectWithSize.
Add the following function to my project, which makes use of the new function on iOS7 and the old one on iOS lower than 7. It has basically the same syntax as sizeWithFont:
-(CGSize)text:(NSString*)text sizeWithFont:(UIFont*)font constrainedToSize:(CGSize)size{
if(IOS_NEWER_OR_EQUAL_TO_7){
NSDictionary *attributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
font, NSFontAttributeName,
nil];
CGRect frame = [text boundingRectWithSize:size
options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
attributes:attributesDictionary
context:nil];
return frame.size;
}else{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
return [text sizeWithFont:font constrainedToSize:size];
#pragma clang diagnostic pop
}
}
You can add that IOS_NEWER_OR_EQUAL_TO_7 on your prefix.pch file in your project as:
#define IOS_NEWER_OR_EQUAL_TO_7 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] >= 7.0 )
I have referred from this link:-
UITableViewCell with UITextView height in iOS 7?
Please check my answer.
Calculate UITableViewCell height to fit string
Here label is used to calculate the height of cell.
When you done with editing of Text in textfield - (void)textViewDidEndEditing:(UITextView *)textView call the tableview reloadData function to update the cell as per text entered in textview
Your will need to manually calculate new size of you textView, and manually call update for your tableView.
static CGFloat cellHeight = 85;//from story board height to
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
if (indexPath.row == 0) {
return cellHeight + [self appendTextViewNewHeight];
}
return cell.bounds.size.height;
}
-(CGFloat) appendTextViewNewHeight {
return _appendHeightForTextView;
}
static CGFloat textViewHeightStartHeight = 33;//from storiboard height
- (void)textViewDidChange:(UITextView *)textView;
{
CGFloat fixedWidth = textView.frame.size.width;
CGSize newSize = [textView sizeThatFits:CGSizeMake(fixedWidth, MAXFLOAT)];
CGRect newFrame = textView.frame;
newFrame.size = CGSizeMake(fmaxf(newSize.width, fixedWidth), newSize.height);
if (newFrame.size.height >= textViewHeightStartHeight) {
CGFloat newAppend = newFrame.size.height - textViewHeightStartHeight;
if (newAppend != self.appendHeightForTextView) {
self.appendHeightForTextView = newAppend;
[self.tableView beginUpdates];
[self.tableView endUpdates];
}
}
}
Also you need to set delegates on storyboards on in the code.
in viedDidLoad you need to do next things:
self.appendHeightForTextView = 0;
And finally set constraints in storyboard for your cell. Do not set bottom constraint of your textView. Only set right, left, and top.

Adjusting elements and the height of UITableView on scroll

I have a UITableView with multiple UILabels. The issue is that the text in these cells change dynamically as I receive data from the server. It works fine when I load the view controller. But as I scroll, the height of the cells are not updated as heightForRowAtIndexPath is only called once.
Here are the screenshots:
As I've shown in the screenshot, the question label reduces in size which leads to a gap (shown by arrow).
Here's my cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIndentifier = #"CustomCell";
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIndentifier];
if (cell == nil)
{
cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIndentifier];
}
cell.question.autoDetectLinks = YES;
// Used to populate cell from NSDictionary
[self setDataToCell:cell AtIndexPath:indexPath];
return cell;
}
Here's my custom cell's layoutSubviews:
- (void) layoutSubviews
{
CGRect frame = self.question.frame;
frame.size.width = 277.0f; //you need to adjust this value
self.question.frame = frame;
self.question.numberOfLines = 2;
[self.question sizeToFit];
// Place time below question
CGRect timeFrame = self.time.frame;
timeFrame.origin.y = self.question.frame.origin.y + self.question.frame.size.height + 5;
self.time.frame = timeFrame;
[self.time sizeToFit];
}
So to tackle this situation I called
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:#[_tableIndexPath] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
in - (void) scrollViewDidScroll:(UIScrollView *)scrollView
This solves my problem but reduces the performance and the elements jump around before settling even after setting the animation as UITableViewRowAnimationNone. Is there a better way of doing it? Should I call reloadRowsAtIndexPaths somewhere else?
Thanks.
Ok here come the edited answer:
The problem is your sizeToFit in your layoutSubviews. Just follow this link to resolve your issue:
here
If you also want the cell and the label to dynamically resize to their corresponding text but at the same time your timelabel to be directly underneath it you will have to determine the size of your uilabel based on the text, font and font-size.
See here for more information:
here

Expanding UITableViewcell Dynamically when enter text on UITextView [duplicate]

This question already has answers here:
How to dynamically resize UITableViewCell height
(4 answers)
Closed 9 years ago.
I have a UITextView in all the cells of a UITableview. The text view's height is increasing dynamically. As the text view size increases, I would like to increase that cell's height.
I am writing as
-(BOOL)textView:(UITextView *)textView1 shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
NSLog(#"textTag%d",textView1.tag);
NSString *stringToSave = [textView1.text stringByReplacingCharactersInRange:range withString:text];
NSLog(#"Save me: %#", stringToSave);
CGFrame*frame =textView1.frame;
frame.size.height = textView1.contentSize.height;
textView1.frame = frame;
//HERE I NEED TO INCREASE THE HIGHT FOR THE PARTICULAR CELL.
if([text isEqualToString:#"\n"])
{
[textView1 resignFirstResponder];
}
return YES;
}
insert these lines:
//class variable, type float
newHeight = textView1.contentSize.height;
//class variable, type int
cellIndex = /*set index of your cell for which you want extended height*/
[yourTable reloadData];
below these lines:
CGFrame*frame =textView1.frame;
frame.size.height = textView1.contentSize.height;
textView1.frame = frame;
And in heightForRowAtIndexPath method
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.row == cellIndex)
{
return newHeight;
}
return regularHeigh;
}
Add a custom growing TextView called HPGrowingTextView to your cell .
Then change the height of the cell as shown in the question
Change the UITableViewCell Height According to Amount of Text
I think you could map the heights of the cells in a NSMutableArray.
The array will contain the standard heights that you have.
You can tag the UITextView with the indexPath.row so you know which item to load from the array.
And you can override the value from the array according with the textview's height.
Then in your
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return [[mycellsizearray objectAtIndex:indexPath.row]floatValue];
}
Now you should have the heights according with your needs.

Resources