Auto-resizing table view cells with button added as subview - ios

Hi I'm able to achieve auto-resizing table view cells (based on amount of text) by pinning textLabel's top, bottom, left and right to content view's top, bottom, left and right. I was able to get different cell height for cell with different text length. But I want to achieve same auto-resizing result with button added as subview to cell. I have added exact same contrains to button as I have it with textLabel. Any help is greatly appreciate .

Summary : Here is an hand-made example about this problem.
First, read the answer about autoresizing tableviewcell with UILabel because you will do like that with a little changes.
The difference between UILabel and UIButton is UILabel has Intrinsic Content Size based on Width and Height. So you need to subclass UIButton and override method :
-(CGSize)intrinsicContentSize {
return CGSizeMake(self.frame.size.width, self.titleLabel.frame.size.height);
}
In your CustomCell class, override method
- (void)layoutSubviews{
[super layoutSubviews]; //btnTest is your Button
[self.contentView setNeedsLayout];
self.btnTest.titleLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.btnTest.titleLabel.frame);
}
In your ViewController :
- (void)configureCell:(UITableViewCell *)cell forRowAtIndexPath: (NSIndexPath *)indexPath{
if ([cell isKindOfClass:[TestCell class]]) {
TestCell *testCell = (TestCell *)cell;
[testCell.btnTest setTitle:#"An example autoresizing UITableViewCell height based on UIButton added as subview by Matie.An example autoresizing UITableViewCell height based on UIButton added as subview by Matie.An example autoresizing UITableViewCell height based on UIButton added as subview by Matie." forState:UIControlStateNormal];
#warning You need to have this below line, to calculate height when the first time viewDidLoad.
testCell.btnTest.titleLabel.text = #"An example autoresizing UITableViewCell height based on UIButton added as subview by Matie.An example autoresizing UITableViewCell height based on UIButton added as subview by Matie.An example autoresizing UITableViewCell height based on UIButton added as subview by Matie.";
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
[self configureCell:self.prototypeCell forRowAtIndexPath:indexPath];
//
self.prototypeCell.bounds = CGRectMake(0.0f, 0.0f, CGRectGetWidth(self.tableView.bounds), CGRectGetHeight(self.prototypeCell.bounds));
[self.prototypeCell setNeedsLayout];
[self.prototypeCell layoutIfNeeded];
CGSize size = [self.prototypeCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
return size.height +1;
}

Related

Change the UIView height which is inside the UITableViewCell

I am trying to change the UIView height which is inside of the tableView. UIView height should not exceed the cell height.
i was trying to set the bounds of the view but it did not effect the view.
how can i fix this and change height of view
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
UIView *view=(UIView *)[cell viewWithTag:999];
view.backgroundColor=[UIColor redColor];
[view setBounds:CGRectMake(view.bounds.origin.x, view.bounds.origin.y, view.bounds.size.width, 400)];
return cell;
}
i found another way to do it. add a identifier to the view height constraints. and i can access it in controller like this.. link -> Is there a way to add an identifier to Auto Layout Constraints in Interface Builder?

Changing UILabel frame height inside tableView cell

I get my UILabel text from remote url, and sometimes the text is too short/too long and I need to adapt my frame size to the text height.
I have implemented costume cell using xib.
This is what I tried so far, which supposed to works, but don't work for a reason I can't understand:
cell.fbLastObject.text = [NSString stringWithFormat:#"%#",update.fbLastObject];
[cell.fbLastObject sizeToFit];
//Cell Size
CGSize labelSize = [cell.fbLastObject.text sizeWithFont:cell.fbLastObject.font
constrainedToSize:cell.fbLastObject.frame.size
lineBreakMode:NSLineBreakByWordWrapping];
labelHeight = labelSize.height;
cell.fbLastObject.frame = CGRectMake(0,0,300,labelHeight);
Anyone has any idea?
For iOS 8 and later, you can use UITableViewAutomaticDimension Put the below code in the viewDidLoad is:
tableView.rowHeight = UITableViewAutomaticDimension;
/* any estimated height but must be more than 2 */
tableView.estimatedRowHeight = 160.0;
tableview.delegate = self;
tableview.dataSource = self;
// you have created the SimpleTableViewCell.xib, So you need to register that cell with table.
UINib *nib = [UINib nibWithNibName:#"SimpleTableViewCell" bundle:nil];
[tableview registerNib:nib forCellReuseIdentifier:#"SimpleTableViewCell"];
Now add proper cell fbLastObject constraints (top, bottom, leading and trailing) pins to super View & set the number of lines to 0
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"SimpleTableViewCell";
SimpleTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
// here set text for your cell label
cell.fbLastObject.text = #"My Text";
[cell setNeedsLayout];
[cell layoutIfNeeded];
return cell;
}
You can try self.tblView.rowHeight = UITableViewAutomaticDimension;
For dynamic cell using autolayout
You can do by mapping Height Constraint of UILabel and calculate the size of the text from remote url and according to that calculated height return height of row and also give that height to mapped Height Constraint outlet and before return cell just write :-
[cell.UILabel updateConstraints];
In your question the steps you took to get the size for the Label is fine. Make Label's property SizeToFit and NumberOfLines to 0 and add the appropriate constraints to it. Then create an instance of NSLayoutConstraint for Height constraint of Label and make it attach to bottom of UITableViewCell. Then when ever you have the CGSize from text then you need to call UpdateConstraintIfNeeded on self and then need to set height constant property for that Label's constraint & need to set the heightForRowAtIndexpath of UITableVIew.
Hope this will work.

layoutSubviews in UIViewTableCell does not work

I have a class PostListTableCell, inheriting UITableViewCell, which is used as my custom cell in a UITableView.
I need to resize some labels in the cell, so I called following method in
- (void)layoutSubviews {
[super layoutSubviews];
[_titleLabel sizeToFit];
}
But the problem is, when the UITableView loaded, the _titleLabel does not resize:
But after I click this cell and select it, the title did resize:
Following is the code to load data:
- (PostListTableCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *PostListTableCellIdentifier = #"PostListTableCell";
PostListTableCell *cell = (PostListTableCell*) [tableView dequeueReusableCellWithIdentifier:PostListTableCellIdentifier];
if (cell == nil) {
cell = [[PostListTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:PostListTableCellIdentifier];
}
Post *post = (Post*)_posts[indexPath.row];
[cell loadPost:post];
return cell;
}
Could anyone help?
The problem is the autolayout that resize again the label for you with the constraints that you had set when you make the label in Interface Build, unfortunately in under autolayout the the hierarchy is Constraints > Frame
First of all, if you use Autolayout in (viewDidLoad) method which is related to UIViewController and its subclasses and (awakeFromNib) which is related to UIView and UITableViewCell etc all Views Frames' have not been rendered yet while those methods called.
So if you want to resize any of outlets you should call it in (ViewDidAppear) for UIViewController. In UIViews and cells you should use:
- (void)layoutSubViews
{
[super layoutSubviews];
}
And don't forget to set interval to your Method of resizing as in this answer.
set frame for your label
-(void)layoutSubviews
{
CGRect frame = CGRectMake(20, 30, 200, 50);
_titleLabel.frame = frame;
}

Resize tableview NSLayoutConstraint

Hi I have a tableView which I change the width programmatically by his constraint:
self.widthTableLeft.constant = self.view.frame.size.width;
I do this in the viewDidLoad.
In the delegate method:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
I need the contentview frame of each cell to calculate the hight of the cell, but when get it, this is the old size, I mean the size if I wouldn't have done the resize.
When the table is showed the size of the table is right but the hight of the cell is wrong.
I have tried to call:
[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];
[cell.contentView setNeedsLayout];
[cell.contentView layoutIfNeeded];
The question is, before to show the view of my view controller, when is the best place to update the width constraint of a UITableView and to get the right contentView in the cells in the method heightForRowAtIndexPath.
Sorry but I'm lost, could you give me any ideas?
Thanksssss
UPDATE
This is the code in heightForRowAtIndexPath
static const NSInteger ROC_TITLE_LABEL_TAG = 2;
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
ROCAgendaItemDetailEntity *agendaItemDetail = [self.listRight objectAtIndex:indexPath.row];
UITableViewCell *cell = [self.tableLeft dequeueReusableCellWithIdentifier:#"cellVideo"];
//I get the label which will make the cell bigger
UILabel *titleLabel = (UILabel *)[cell viewWithTag:ROC_TITLE_LABEL_TAG];
//We init the height title with the min height.
float extraSpaceHeightLabel = 0;
if (agendaItemDetail.agendaItem.title.length > 0) {
//I will use his width to get the hight that I need to write all text
float width = titleLabel.frame.size.width;
CGSize size = CGSizeMake(width, CGFLOAT_MAX);
//we get the size
CGSize sizeTitleLabel = [agendaItemDetail.agendaItem.title sizeWithFont:[ROCTextsInformation imagoMed:15] constrainedToSize:size lineBreakMode:titleLabel.lineBreakMode];
//we substract the current height of the label to know the extra space to write all text
sizeTitleLabel.height -= titleLabel.frame.size.height;
extraSpaceHeightLabel = sizeTitleLabel.height;
}
//The final hight will be the contenViewHeight pluss the extra space needed.
return cell.contentView.frame.size.height + extraSpaceHeightLabel;
}
and this is the cell in the table view
Thanks again
viewDidLoad is too early to try and access the geometries of your views. Instead, access self.view's width in viewDidLayoutSubviews.
#interface CustomViewController ()
#property (nonatomic) BOOL isFirstTimeViewDidLayoutSubviews; // variable name could be re-factored
#end
#implementation CustomViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.isFirstTimeViewDidLayoutSubviews = YES;
}
- (void)viewDidLayoutSubviews
{
// only after layoutSubviews executes for subviews, do constraints and frames agree (WWDC 2012 video "Best Practices for Mastering Auto Layout")
if (self.isFirstTimeViewDidLayoutSubviews) {
// execute geometry-related code...
self.widthTableLeft.constant = self.view.frame.size.width;
}
self.isFirstTimeViewDidLayoutSubviews = NO;
}

Resizing custom UITableViewCell's subviews on creation

I'm attempting to create a custom UITableViewCell with its own XIB, of which contains two important, editable components:
UILabel
UIImage with 'end-cap insets' - this image sits behind the label, and resizes with it
When I create my UITableViewCell I can set its label's text easily, but in the same method I also try to change the UIImage's frame to match that of the UILabel's. However, this is not happening until I 'reload' the cell by scrolling the table view to dequeue it and bring it back into view.
I create the custom table view cell in my view controller's .m:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *UITableViewCellIdentifier = #"msgCell";
RMMessageCell *cell = [tableView dequeueReusableCellWithIdentifier:UITableViewCellIdentifier];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"MessageCell" owner:self options:nil];
cell = [topLevelObjects objectAtIndex:0];
[cell customInit]; //This sets up the ImageView's image etc
}
[cell setMessageValue:[_messages objectAtIndex:indexPath.row]]; //SEE BELOW
return cell;
}
...And in my custom cell's .m, I deal with setting the text label and resizing the image with this method:
- (void)setMessageValue:(NSString *)message {
_testLabel.text = message;
// Assume the text label's frame has already been set to the message's length
// (will add this in once I figure out how to change the imageView's
// frame correctly)
// Set the image view's frame to the label's
// THIS DOES NOT TAKE EFFECT UNTIL THE TABLE VIEW IS RE-SCROLLED
CGRect frame = _imageView.frame;
frame.size.width = _testLabel.frame.size.width + 8;
_imageView.frame = frame;
}
This is caused because a table view cell is created at one size, and then it is resized when it is displayed after being added to the table. If you log the bounds or frame of your cell, you will see that it is one size (smaller) when you load it from the nib, and another size (bigger) when you "refresh" the cell by scrolling it off of the screen and back on.
The simplest approach would be to make sure that the label and image both have the same auto-sizing rules, so that when the cell is resized, they both grow together.
you can use UITableView delegate method,
– (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
inside this you can set the height of row dynamically like..
// This is only for Example that you can set your cell height
-(CGFloat)tableView:(UITableView *)aTableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *text;
text = [_messages objectAtIndex:indexPath.row];
CGSize constraint = CGSizeMake(280, 2000);
CGSize size = [text sizeWithFont:[UIFont boldSystemFontOfSize:12] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];
return size.height + 5;
}
You should be able to control the size of the subviews if you programmatically create them and add them to your tableview cell (i.e.,so that they are not set in storyboard, and thus are not subjected to explicit auto-contraints).
In my implementation, I created a customCell subclass. In the .h:
#property (strong, nonatomic) UILabel *customLabel;
Then in the .m:
- (id)initWithCoder:(NSCoder *)aDecoder {
METHOD;
self = [super initWithCoder:aDecoder];
if (self) {
// Initialization code
self.customLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320, 40)];
[self addSubview:self.customLabel];
}
return self;
}
In your tableViewController's .m file, in the method tableView:cellForRowAtAtIndexPath:
theCell.customLabel.frame = CGRectMake(0, 0, 320, 40);
theCell.customLabel.text = #"Whatever text you want";
This will give you instant and complete control over your custom label right when the tableview and cell loads.
In response to #inafziger, I tried programmatically removing the constraints on the label but it did not resolve this auto-resizing issue.
Update: making a temporary reference to the subview, then removing it from superview, and then adding it back to the subview, this worked just as well, with the slight exception that the in my case where I'm using a label, the height of the label was fit to the height of the text it contained (whereas programmatically creating the label in my example above, the label will have whatever height you assign it.) The advantage being that you don't have to create any custom labels, or even touch the subclass tableviewCell. Just use whatever you created in storyboard. Here's tableView:cellForRowAtIndexPath:
UILabel *theLabel = theCell.theLabel;
[theCell.theLabel removeFromSuperview];
[theCell addSubview:theLabel];
theCell.theLabel.frame = CGRectMake(0, 0, 320, 40);

Resources