increase uitableviewcell height simultaneously increasing the inner UITextView - ios

I create a UITableView with different types of UITableViewCell depending on the type of content to display. One of this is a UITableViewCell with inside an UITextView programmatically created in this way:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
...
if([current_field.tipo_campo isEqualToString:#"text_area"])
{
NSString *string = current_field.valore;
CGSize stringSize = [string sizeWithFont:[UIFont boldSystemFontOfSize:15] constrainedToSize:CGSizeMake(320, 9999) lineBreakMode:UILineBreakModeWordWrap];
CGFloat height = ([string isEqualToString:#""]) ? 30.0f : stringSize.height+10;
UITextView *textView=[[UITextView alloc] initWithFrame:CGRectMake(5, 5, 290, height)];
textView.font = [UIFont systemFontOfSize:15.0];
textView.text = string;
textView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
textView.textColor=[UIColor blackColor];
textView.delegate = self;
textView.tag = indexPath.section;
[cell.contentView addSubview:textView];
[textView release];
return cell;
}
...
}
Since the text view is editable the cell that contains it should change its height to correctly fit the text view sizes. Initially I did this by resizing the UITextView inside the method textViewDidChange:, in this way:
- (void)textViewDidChange:(UITextView *)textView
{
NSInteger index = textView.tag;
Field* field = (Field*)[[self sortFields] objectAtIndex:index];
field.valore = textView.text;
[self.tableView beginUpdates];
CGRect frame = textView.frame;
frame.size.height = textView.contentSize.height;
textView.frame = frame;
newHeight = textView.contentSize.height;
[self.tableView endUpdates];
}
I save the new height of text view in a variable and then when tableView:heightForRowAtIndexPath: method is called, I resize the cell in this way:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
...
if ([current_field.tipo_campo isEqualToString:#"text_area"])
{
return newHeight +10.0f;
}
else
return 44.0f;
...
}
In this way both are resized but is not done in sync, ie first the TextView is resized and then it is resized the height of the cell, so for an instant the user see that the text view is larger than the cell. How can I fix this bad behavior?

I have created one demo for your problem, hope will help you.
My idea of solution is using AutoResizingMask of UITextView.
My .h file
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController<UITabBarDelegate, UITableViewDataSource, UITextViewDelegate>{
IBOutlet UITableView *tlbView;
float height;
}
#end
And my .m file (Includes only required methods)
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
height = 44.0;
}
- (void)textViewDidChange:(UITextView *)textView{
[tlbView beginUpdates];
height = textView.contentSize.height;
[tlbView endUpdates];
}
#pragma mark - TableView datasource & delegates
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return 1;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
if (indexPath.row==0) {
if (height>44.0) {
return height + 4.0;
}
}
return 44.0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"CellIdentifier"];
UITextView *txtView = [[UITextView alloc] initWithFrame:CGRectMake(0.0, 2.0, 320.0, 40.0)];
[txtView setDelegate:self];
[txtView setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight]; // It will automatically resize TextView as cell resizes.
txtView.backgroundColor = [UIColor yellowColor]; // Just because it is my favourite
[cell.contentView addSubview:txtView];
return cell;
}
Hope it will help you out.

To resize the cells you would use code similar to this
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
NSString *newText = [textView.text stringByReplacingCharactersInRange:range withString:text];
CGSize size = // calculate size of new text
CGRect frame = textView.frame;
frame.size.height = textView.contentSize.height;
textView.frame = frame;
if ((NSInteger)size.height != (NSInteger)[self tableView:nil heightForRowAtIndexPath:nil]) {
// if new size is different to old size resize cells.
[self.tableView beginUpdates];
[self.tableView endUpdates];
}
return YES;
}

Set the TextView Frame With An Animation ..so that it syncs with the cell's animation of expanding height

Check this out: UIView Contentmode - play with the values like:
cell.contentMode = //...//

- (void)textViewDidChange:(UITextView *)textView
{
UITableViewCell *cell = (UITableViewCell*)textView.superview.superview;
if (cell.frame.size.height < textView.contentSize.height) {
[self.tableView beginUpdates];
CGRect frame = textView.frame;
frame.size.height = textView.contentSize.height;
textView.frame = frame;
CGRect cellFrame = cell.frame;
cellFrame.size.height = textView.frame.size.height;
cell.frame = cellFrame;
[self.tableView endUpdates];
}
}

Siba Prasad Hota's code probably will do the trick (You need reference to table view from cell level), but I have another, longer approach. I always do such stuff in this way, because I like to have all things separated (MVC pattern).
If I were You, I would do this like that (code from head):
Cell parent protocol:
#protocol CellParent <NSObject>
#required
#property (nonatomic, strong) UITableView *tableView;
#end
Cell model:
#interface CellModel
#property (nonatomic, assign) BOOL hasTextView;
#property (nonatomic, strong) NSString *textViewContent;
-(float)getCurrentHeightForCell;//implement calculating current height of cell. probably 2 * SOME_MARGIN + height of temporary textView with textViewContent variable
Cell
#interface MyCell
#property (nonatomic, strong) CellModel *dataModel;
#property (nonatomic, weak) id<CellParent> parent;
#property (nonatomic, strong) UITextView *textView;
- (id)initWithStyle:(UITableViewCellStyle)style andModel:(CellModel*) model;
with implementations like this:
(id)initWithStyle:(UITableViewCellStyle)style andModel:(CellModel*) model
{
self = [super initWithStyle:style reuseIdentifier:#"MyCell"];
if (self)
{
[[NSBundle mainBundle] loadNibNamed:#"MyCell" owner:self options:nil];
self.dataModel = model;
}
return self;
}
-(void) setDataModel:(CellModel *)dataModel
{
_dataModel = dataModel;
if(_dataModel.hasTextView)
{
//show text view
}
else
{
//hide text view
}
//do other cell modifications
}
-(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
self.dataModel.textViewContent = textView.text;
[self.parent.tableView beginUpdates];
[self.parent.tableView endUpdates];
return YES;
}
Controller with table view
-(UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
MyCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MyCell"];
if (cell == nil)
{
cell = [[MyCell alloc] initWithStyle:UITableViewCellStyleDefault andModel: [self.cellsModels objectAtIndex:indexPath.row]];
}
cell.dataModel = [self.cellsModels objectAtIndex:indexPath.row];
cell.parent = self;
return cell;
}
-(CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return [((CellModel*)[self.tableContentArray objectAtIndex:indexPath.row]) getCurrentHeightForCell];
}

You should calculate newHeight for cell before loading cell. Instead of calculating newHeight in textViewDidChange, calculate it in heightForRowAtIndexPath and return same as
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([current_field.tipo_campo isEqualToString:#"text_area"])
{
NSString *string = current_field.valore;
CGSize stringSize = [string sizeWithFont:[UIFont boldSystemFontOfSize:15] constrainedToSize:CGSizeMake(320, 9999) lineBreakMode:UILineBreakModeWordWrap];
CGFloat height = ([string isEqualToString:#""]) ? 30.0f : stringSize.height+10;
return height + 10.0f;
}
else
{
return 44.0f;
}
}

I would not bother with cells height using method
(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
and rather made your view text field delegate and handle the following event in a way shown below:
- (void) textFieldDidResize:(id)sender
{
[self.tableView beginUpdates];
[self.tableView endUpdates];
}
Also make sure that you did the following:
yourInputField.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
Then, the only one thing you need is to resize your text field. Your cells in tableview will adopt to the size of inner text field. Just add it as subview to cell.contentView.

Related

How to increase label or text view size (height and width) in tableview by objective c(For Conversation Page) Can you Help me?

I can't Increase Label or Textview Size in table view by objective c.
I'm Struck for this problem.
Finally i found the answer with easy method using contraints(set maximum and minimum width and height for label)Thats the output
Adding up my code ..
#pragma mark - TABLE VIEW DELEGATE
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"ChatCell";
ChatCell *cell = (ChatCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[ChatCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
cell.txtView.text=[messages objectAtIndex:indexPath.row];
if(indexPath.row%2){
cell.txtView.backgroundColor=[UIColor whiteColor];
cell.leading.constant=0.0f;
}else{
cell.txtView.backgroundColor=[UIColor colorWithRed:246.0f/255 green:190.0f/255 blue:175.0f/255 alpha:1.0f];
cell.leading.constant=((tblView.frame.size.width)/2)-50-16;
}
[cell.subView.layer setShadowColor:[UIColor grayColor].CGColor];
[cell.subView.layer setShadowOpacity:1.0f];
[cell.subView.layer setShadowRadius:0.0f];
[cell.subView.layer setShadowOffset:CGSizeMake(0, 2.0)];
[cell.txtView.layer setCornerRadius:10.0f];
[cell.txtView.layer setMasksToBounds:YES];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
NSDictionary *attributesName = #{NSFontAttributeName: [UIFont fontWithName:#".SFUIText-Regular" size:14.0f]};
CGRect r1 = [[messages objectAtIndex:indexPath.row] boundingRectWithSize:CGSizeMake((tblView.frame.size.width/2)+50, 0)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:attributesName
context:nil];
return r1.size.height+70;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [messages count];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
Adding the ChatCell properties list. Cell contains a subView and textview with in subview(top, leading, bottom, trailing of textview all connected to subview) and leading is the auto layout constraint connecting superview and subview leading end.
#property(nonatomic,weak) IBOutlet UITextView *txtView;
#property(nonatomic,weak) IBOutlet UILabel *lblDate;
#property(nonatomic,weak) IBOutlet UIView *subView;
#property(nonatomic,weak) IBOutlet NSLayoutConstraint *leading;
If you use textview
-(void)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);
NSLog(#"this is updating height%#",NSStringFromCGSize(newFrame.size));
height=newFrame.size.height;
}
Get the height from this method then set it to heightforrow method
Set constraints for the textview leading,trailing,top,bottom.

Change height of tableview cell according to label text in objective c

I am making one simple map based application. There are two labels in the custom cell of table view. One of label's text is dynamic and I want to change the cell's height according to label's text and height.
-(CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
NSMutableString *strauditType = #"Your String ";
CGRect textRect = [strauditType boundingRectWithSize:maximumLabelSize
options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
attributes:#{NSFontAttributeName:[UIFont systemFontOfSize:14.0]}
context:nil];
CGSize messageSize = textRect.size;
return messageSize.height + 10.0f;
}
-(CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewAutomaticDimension;
}
I tried and got the solution simply.
ViewController.m
#import "ViewController.h"
#import "CustomTableViewCell.h"
#interface ViewController ()<UITableViewDataSource,UITableViewDelegate>
{
NSMutableArray *array;
}
#property (strong, nonatomic) IBOutlet UITableView *tableViewIncreaseRowHeight;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIFont *labelFont = [UIFont fontWithName:#"Noteworthy-Bold" size:20];
NSDictionary *arialdict = [NSDictionary dictionaryWithObject:labelFont forKey:NSFontAttributeName];
NSMutableAttributedString *message = [[NSMutableAttributedString alloc] initWithString:#"this is just the sample example of how to calculate the dynamic height for tableview cell which is of around 7 to 8 lines. you will need to set the height of this string first, not seems to be calculated in cellForRowAtIndexPath method." attributes:arialdict];
array = [NSMutableArray arrayWithObjects:message, nil];
NSMutableAttributedString *message_1 = [[NSMutableAttributedString alloc] initWithString:#"you will need to set the height of this string first, not seems to be calculated in cellForRowAtIndexPath method." attributes:arialdict];
[array addObject:message_1];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//table view delegate and data source methods
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomTableViewCell *cell = (CustomTableViewCell *)[tableView dequeueReusableHeaderFooterViewWithIdentifier:#"cell"];
NSArray *arr = [[NSBundle mainBundle]loadNibNamed:#"CustomTableViewCell" owner:self options:nil];
if(cell==nil)
{
cell = arr[0];
}
cell.labelName.attributedText = array[indexPath.row] ;
cell.labelName.numberOfLines = 2;
[cell.labelName sizeToFit];
cell.labelID.text = #"20";
return cell;
}
-(float)height :(NSMutableAttributedString*)string
{
NSAttributedString *attributedText = string;
//you need to specify the some width, height will be calculated
CGRect rect = [attributedText boundingRectWithSize:(CGSize){225, MAXFLOAT}
options:NSStringDrawingUsesLineFragmentOrigin
context:nil];
CGSize requiredSize = rect.size;
//finally u return your height
return requiredSize.height;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
//whatever the height u need to calculate calculate hear only
CGFloat heightOfcell = [self height:array[indexPath.row]];
NSLog(#"%f",heightOfcell);
return heightOfcell;
}
#end
Credits go to Shan
Source
Thank you so much:-)

Unable add UIVIew to UITableView Cell Programmatically

I am trying to create a Card Based News feed (Similar to Facebook app) in iOS.I'm implementing programmatically because the height of UITablecell has to increase/decrease based on the data.
Consider i have one UIlabel and one UIImageView added, then the height of UITablecell should be adjusted based on the fields. If one more text feild is added then height has to increase and if imageview is removed then height has to decrease.
The issue here is I couldn't to add CustomView on the UItablecell programmatically but when i create using Interface builder then its working fine but the height remains constant which i don't want to have.
Can some one please help me out.
TableViewCell.h
#interface TableViewCell : UITableViewCell
#property (strong,nonatomic) UIView *customView;
#property (strong,nonatomic) UILabel *customLabel;
#property (strong,nonatomic) UIImageView *customImage;
#end
TableViewCell.m
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// configure control(s)
[self addSubview:self.customView];
[self.customView addSubview:self.customLabel];
[self.customView addSubview:self.customImage];
}
return self;
}
- (UIView *)customView
{
if (!_customView)
{
_customView = [[UIView alloc] initWithFrame:CGRectMake(0, 10, self.contentView.frame.size.width, 50)];
[_customView setTranslatesAutoresizingMaskIntoConstraints:NO];
}
return _customView;
}
- (UIImageView *)customImage
{
if (!_customImage)
{
_customImage = [UIImageView new];
_customImage.clipsToBounds = YES;
[_customImage.layer setBorderColor: [[UIColor grayColor] CGColor]];
[_customImage.layer setBorderWidth: 1.0];
_customImage.contentMode = UIViewContentModeCenter;
[_customImage setTranslatesAutoresizingMaskIntoConstraints:NO];
}
return _customImage;
}
- (UILabel *)customLabel
{
if (!_customLabel)
{
_customLabel = [UILabel new];
[_customLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
}
return _customLabel;
}
UITableVIewController.m
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath: (NSIndexPath *)indexPath
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (!_stubCell)
{
_stubCell = [tableView dequeueReusableCellWithIdentifier:#"TableCell"];
}
});
CGFloat height = [_stubCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
return height + 1;
}
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 50.f;
}
- (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"TableCell";
// Similar to UITableViewCell, but
_stubCell = (TableViewCell *)[theTableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (_stubCell == nil) {
_stubCell = [[TableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
// Just want to test, so I hardcode the data
_stubCell.customLabel.text = #"Testing";
return cell;
}
I think it may be better to create multiple nibs for the same class UITableViewCell, one for each of the possible layouts that you need. Depending on which nib is used then set heightForRowAtIndexPath to the height of the nib.
This will give you predictability of the layout for each situation and you connect only the fields defined in UITableViewCell in cellForRowAtIndexPath.
never mind i found answer by myself. I am calculating the height of each UIView that is added the super view. Based on the total height the UITableview height increases and decrease and also using auto layout adjusting the layout constraints made me simple.
I am still working on the design once its done i'll post the code so that it will be help ful for other developers.

Change width of TableView or TableViewCell

Hey everybody :) i try to change the width of my cells so there is a little space between the cells and the tableview border. I tried everything i could found here on stackoverflow, but without success.
I created the tableview with the interface builder, so first i simple tried to set the tableview size to "freeform" and dragged the width to 300.0f, but nothing happenend. Than i tried to do it programmatically in my "viewDidLoad" with:
self.tableView.frame = CGRectMake(10.0f, self.tableView.frame.origin.y, 300.0f, self.tableView.frame.size.height);
but here also nothing happens.... than i tried to change the cells directly with:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
GTNewsCustomCell *newsCell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier1];
newsCell.contentView.frame = CGRectMake(10.0f, 0, 300, newsCell.frame.size.height);
}
but same Problem here....any ideas what I missing?
EDIT: Another Solution for this Problem is to change the frame of the Custom Cell with:
- (void)setFrame:(CGRect)frame {
frame.origin.x += inset;
frame.size.width -= 2 * inset;
[super setFrame:frame];
}
just try this
in your custom cell put a property like
in .h file
#interface GTNewsCustomCell : UITableViewCell
#property (nonatomic, assign)CGRect cellFrame;
in .m file
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
self.backgroundColor = [UIColor greenColor];//for testing purpose only
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
//automatically called
- (void)layoutSubviews
{
[super layoutSubviews];
CGRect cellRect = self.bounds;
cellRect.size.width = self.cellFrame.size.width;
self.bounds = cellRect;
}
.in .m of viewController
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
GTNewsCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
if(cell == nil)
{
cell = [[GTNewsCustomCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
}
cell.cellFrame = CGRectMake(10, 0, tableRect.size.width,40);//hear tableRect is the frame of your tableview
return cell;
}
not sure try this hope this helps u
For this, first of all you can take an UIImageView to cover your full view and set its image as a bordered image. Now add a table view on this imageview with making width so as the borders of this image is visible.
I think you want dynamic Height for the Tableviewcell instead of width.
Delegate method of UITableView will help on this:
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
Which will return height of every cell. You can implement it as following sample code. This is showing dynamic height on the basis of dynamic text content.
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
//set width depending on device orientation
self.cellPrototype.frame = CGRectMake(self.cellPrototype.frame.origin.x, self.cellPrototype.frame.origin.y, tableView.frame.size.width, self.cellPrototype.frame.size.height);
CGFloat quotationLabelHeight = [self sizeOfLabel:self.cellPrototype.quotationLabel withText:[self quotationTextForRow:indexPath.row]].height;
CGFloat attributionLabelHeight = [self sizeOfLabel:self.cellPrototype.attributionLabel withText:[self attributionTextForRow:indexPath.row]].height;
CGFloat padding = self.cellPrototype.quotationLabel.frame.origin.y;
CGFloat combinedHeight = padding + quotationLabelHeight + padding/2 + attributionLabelHeight + padding;
CGFloat minHeight = padding + self.cellPrototype.avatarButton.frame.size.height + padding;
return MAX(combinedHeight, minHeight);
}
You can try with this too.
Use this:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
delegate method of UITableView and return a float value (CellHight+space bw cells).

Dynamically resizing UITableViewCell based on text input

I am trying to dynamically resize some UITableViewCell's based on the height of UITextView's contained within them.
There's loads of solutions to this by keeping a pointer to the UITextView and getting it's content size in heightForRowAtIndexPath however when the whole table is created dynamically with an unknown number of rows and an unknown number of them rows contain UITextView's this just isn't possible.
It would be easy if I could call the cell in question during heightForRowAtIndexPath but that causes an infinite loop and crash as this method is called before any cell's are even created.
Any other solutions?
I am using a UITableViewCell subclass for my cell like this:
- (void)initalizeInputView {
// Initialization code
self.selectionStyle = UITableViewCellSelectionStyleNone;
self.textView = [[UITextView alloc] initWithFrame:CGRectZero];
self.textView.autocorrectionType = UITextAutocorrectionTypeDefault;
self.textView.autocapitalizationType = UITextAutocapitalizationTypeNone;
self.textView.textAlignment = NSTextAlignmentRight;
self.textView.textColor = [UIColor lightBlueColor];
self.textView.font = [UIFont fontWithName:#"HelveticaNeue-Light" size:17];
self.textView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
self.textView.keyboardType = UIKeyboardTypeDefault;
[self addSubview:self.textView];
self.textView.delegate = self;
}
- (BOOL)resignFirstResponder {
if (_delegate && [_delegate respondsToSelector:#selector(tableViewCell:didEndEditingWithLongString:)]) {
[_delegate tableViewCell:self didEndEditingWithLongString:self.stringValue];
}
return [super resignFirstResponder];
}
- (void)setKeyboardType:(UIKeyboardType)keyboardType
{
self.textView.keyboardType = keyboardType;
}
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
[self initalizeInputView];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self initalizeInputView];
}
return self;
}
- (void)setSelected:(BOOL)selected {
[super setSelected:selected];
if (selected) {
[self.textView becomeFirstResponder];
}
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
if (selected) {
[self.textView becomeFirstResponder];
}
}
- (void)setStringValue:(NSString *)value {
self.textView.text = value;
}
- (NSString *)stringValue {
return self.textView.text;
}
- (void)textViewDidBeginEditing:(UITextView *)textView
{
// For keyboard scroll
UITableView *tableView = (UITableView *)self.superview;
AppSetupViewController *parent = (AppSetupViewController *)_delegate;
parent.activeCellIndexPath = [tableView indexPathForCell:self];
}
- (void)textViewDidChange:(UITextView *)textView
{
if (textView.contentSize.height > contentRowHeight) {
contentRowHeight = textView.contentSize.height;
UITableView *tableView = (UITableView *)self.superview;
[tableView beginUpdates];
[tableView endUpdates];
[textView setFrame:CGRectMake(0, 0, 300.0, textView.contentSize.height)];
}
}
- (void)textViewDidEndEditing:(UITextView *)textView
{
if (_delegate && [_delegate respondsToSelector:#selector(tableViewCell:didEndEditingWithLongString:)]) {
[_delegate tableViewCell:self didEndEditingWithLongString:self.stringValue];
}
UITableView *tableView = (UITableView *)self.superview;
[tableView deselectRowAtIndexPath:[tableView indexPathForCell:self] animated:YES];
}
- (void)layoutSubviews {
[super layoutSubviews];
CGRect editFrame = CGRectInset(self.contentView.frame, 10, 10);
if (self.textLabel.text && [self.textLabel.text length] != 0) {
CGSize textSize = [self.textLabel sizeThatFits:CGSizeZero];
editFrame.origin.x += textSize.width + 10;
editFrame.size.width -= textSize.width + 10;
self.textView.textAlignment = NSTextAlignmentRight;
} else {
self.textView.textAlignment = NSTextAlignmentLeft;
}
self.textView.frame = editFrame;
}
Which is created in cellForRowAtIndexPath like this:
else if ([paramType isEqualToString:#"longString"]) {
MyIdentifier = #"AppActionLongString";
LongStringInputTableViewCell *cell = (LongStringInputTableViewCell *)[tableView dequeueReusableCellWithIdentifier:MyIdentifier];
cell.textLabel.text = [[[_selectedAction objectForKey:#"parameters"] objectAtIndex:indexPath.row] objectForKey:#"name"];
cell.params = [[_selectedAction objectForKey:#"parameters"] objectAtIndex:indexPath.row];
cell.textView.text = [results objectAtIndex:indexPath.row];
return cell;
}
Simply passing back the height to a variable in my ViewController is no good because like I said, there could be several of these cells within the table.
Thanks
Use this method to dynamically resize your tableviewCell. First store the user input in NSMutable Array and after that reload table. Hope it will help you.
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *msg =[self.messages objectAtIndex:indexPath.row];
CGSize textSize = { 120, 10000.0 };
CGSize size = [msg sizeWithFont:[UIFont systemFontOfSize:15]
constrainedToSize:textSize
lineBreakMode:UILineBreakModeWordWrap];
return size.height+20;
}
I needed a dynamic table view cell height based on the amount of text to be displayed in that cell. I solved it in this way:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (!isLoading)
{
if ([self.conditionsDataArray count]>0)
{
Conditions *condition =[self.conditionsDataArray objectAtIndex:indexPath.row];
int height;
UITextView *textview = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, 236, 0)]; //you can set your frame according to your need
textview.text = condition.comment;
textview.autoresizingMask = UIViewAutoresizingFlexibleHeight;
[tableView addSubview:textview];
textview.hidden = YES;
height = textview.contentSize.height;
NSLog(#"TEXT VIEW HEIGHT %f", textview.contentSize.height);
[textview removeFromSuperview];
[textview release];
return height;
}
return 55; //Default height, if data is in loading state
}
Notice that the Text View has been added as Subview and then made hidden, so make sure you add it as SubView otherwise it's height will not be considered.
It would be easy if I could call the cell in question during heightForRowAtIndexPath but that causes an infinite loop and crash as this method is called before any cell's are even created. Any other solutions?
You can. I would guess you're attempting to call cellForRowAtIndexPath, which will cause an infinite loop. But you should rather be dequeuing the cell directly by calling dequeueReusableCellWithIdentifier.
See the table view delegate implementation of TLIndexPathTools. The heightForRowAtIndexPath method looks like this:
(EDIT Initially forgot to include the method prototypeForCellIdentifier that actually dequeues the cell.)
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
id item = [self.dataModel itemAtIndexPath:indexPath];
NSString *cellId = [self cellIdentifierAtIndexPath:indexPath];
if (cellId) {
UITableViewCell *cell = [self prototypeForCellIdentifier:cellId];
if ([cell conformsToProtocol:#protocol(TLDynamicSizeView)]) {
id<TLDynamicSizeView> v = (id<TLDynamicSizeView>)cell;
id data;
if ([item isKindOfClass:[TLIndexPathItem class]]) {
TLIndexPathItem *i = (TLIndexPathItem *)item;
data = i.data;
} else {
data = item;
}
CGSize computedSize = [v sizeWithData:data];
return computedSize.height;
} else {
return cell.bounds.size.height;
}
}
return 44.0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView prototypeForCellIdentifier:(NSString *)cellIdentifier
{
UITableViewCell *cell;
if (cellIdentifier) {
cell = [self.prototypeCells objectForKey:cellIdentifier];
if (!cell) {
if (!self.prototypeCells) {
self.prototypeCells = [[NSMutableDictionary alloc] init];
}
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
//TODO this will fail if multiple tables are being used and they have
//overlapping identifiers. The key needs to be unique to the table
[self.prototypeCells setObject:cell forKey:cellIdentifier];
}
}
return cell;
}
This uses a protocol TLDynamicSizeView that any cell can implement to have it's height calculated automatically. Here is a working example project. The cell's implementation of the protocol looks like this:
#implementation DynamicHeightCell
- (void)awakeFromNib
{
[super awakeFromNib];
self.originalSize = self.bounds.size;
self.originalLabelSize = self.label.bounds.size;
}
- (void)configureWithText:(NSString *)text
{
self.label.text = text;
[self.label sizeToFit];
}
#pragma mark - TLDynamicSizeView
- (CGSize)sizeWithData:(id)data
{
[self configureWithText:data];
//the dynamic size is calculated by taking the original size and incrementing
//by the change in the label's size after configuring
CGSize labelSize = self.label.bounds.size;
CGSize size = self.originalSize;
size.width += labelSize.width - self.originalLabelSize.width;
size.height += labelSize.height - self.originalLabelSize.height;
return size;
}
#end
just comment
if (cell == nil)
Hope, this will help you.

Resources