So I have looked over this answer. But I am still not getting the heights to return correctly for iOS7. I have a table view with a cell that I laid out in autolayout that is fairly complicated. Whenever I try to override the heightForRowAtIndex (to make it iOS7 compatible) I get row heights that don't seem to be calculated correctly. When I don't override heightForRowAtIndex everything works great, except that it doesn't work on iOS7. I am also trying to layout the whole thing automatically using xibs. There isn't really any logic in my DipticCell.m. It's all in the UITableView subclass.
-(id)init{
//Implementation details go BELOW
self.dataSource = self;
self.delegate = self;
[self registerNib:[UINib nibWithNibName:#"DipticCell" bundle:nil] forCellReuseIdentifier:#"dipticCell"];
[self registerClass:[UITableViewCell class] forCellReuseIdentifier:#"cell2"];
self.rowHeight = UITableViewAutomaticDimension;
offScreenCells = [[NSMutableDictionary alloc] init];
return self;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *reuseIdentifier = #"dipticCell";
if (indexPath.row > 0){
reuseIdentifier = #"cell2";
}
UITableViewCell *cell = [offScreenCells objectForKey:reuseIdentifier];
if (!cell) {
cell = [self dequeueReusableCellWithIdentifier:reuseIdentifier];
[offScreenCells setObject:cell forKey:reuseIdentifier];
}
[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];
cell.bounds = CGRectMake(0.0f, 0.0f, CGRectGetWidth(tableView.bounds), CGRectGetHeight(cell.bounds));
[cell setNeedsLayout];
[cell layoutIfNeeded];
CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
height += 1.0f;
return height;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
if (indexPath.row == 0){
DipticCell *cell = [tableView dequeueReusableCellWithIdentifier:#"dipticCell"];
if (cell == nil) {
cell = [[DipticCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"dipticCell"];
}
return cell;
}else{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell2"];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"cell2"];
}
cell.textLabel.text = #"one";
return cell;
}
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return 10;
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
Just to confirm that everything is in the contentView.
Also, when I override the heightForRowAtIndexPath I get an "Unable to simultaneously satisfy constraints." warning. But when I don't override that then things seem to work (which makes sense because the cell should just adapt to the height of the content and now I'm trying to override it with a height of 1.)
Here is a link to the project if you want to run it. AutoLayoutCells
What worked for me most of the time is to make sure, that you have a constraint path going from the top of the cell down to the bottom of the cell.
So if your cell as three labels: label1, label2, label3 and all shall be displayed below each other. Than add constraints:
cell.top to label1.top
label1.bottom to label2.top
label2.bottom to label3.top
label3.bottom to cell.bottom
that way the height of your cell is defined by constraints. So make sure to connect all your subviews that define the height of the cell in such a chain.
Related
How to increase cell height based on the label text(Dynamic) in cell.In the below code lblAnswer is getting dynammic data, based on this the cell height should increase. Tried below code, but doesn't work for me. TIA
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
EmpViewCell *cell = (EmpViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[EmpViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.lblAnswer.lineBreakMode = NSLineBreakByWordWrapping;
cell.lblAnswer.numberOfLines = 0;
[cell setSelectionStyle:UITableViewCellSelectionStyleGray];
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"EmpViewCell" owner:self options:nil];
for (id currentObject in topLevelObjects){
if ([currentObject isKindOfClass:[UITableViewCell class]]){
cell = (EmpViewCell *) currentObject;
cell.selectionStyle=UITableViewCellSelectionStyleNone;
}
}
}
NSMutableDictionary* emmpdict = [_emparr objectAtIndex:indexPath.row];
cell.lblEmpName.text = [NSString stringWithFormat:#"%#",[emmpdict objectForKey:#"EmployeeName"]];
cell.lblQuestion.text=[NSString stringWithFormat:#"%#",[emmpdict objectForKey:#"Question"]];
cell.lblAnswer.text=[NSString stringWithFormat:#"%#",[emmpdict objectForKey:#"Answer"]];
return cell;
}
You easily achieve this by using UITableViewAutomaticDimension.
Just use below code:
your_tableView.estimatedRowHeight = 100; //or any temorary value as it is going to be replaced after getting dynamic height
your_tableView.rowHeight = UITableViewAutomaticDimension;
NOTE: To work this properly, make sure to apply your all constraints in tableViewCell properly
If you have added UILabel inside Storyboard to UITableviewCell, then won't get cell as nil. Then some of your code won't execute i.e., if(cell == nil) because cell is not nil.
In Storyboard do this changes:
Make sure you have given top, bottom, leading and trailing constrains to the UILabel to UITableViewCell contentView.
Then set number of lines to UILabel to '0' also Line Break to "Word Wrap".
In Controller for UITableViewDelegate heightForRow method:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
tableView.estimatedRowHeight = 100;
return UITableViewAutomaticDimension;
}
This will help to solve above requirement.
For new iOS 8 there is a new way to make this simple.
Objective c:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.tableView.estimatedRowHeight = 40.0; // for example. Set your average height
self.tableView.rowHeight = UITableViewAutomaticDimension;
[self.tableView reloadData];
}
swift 3.0 :
override func viewWillAppear(animated: Bool) {
self.tableView.estimatedRowHeight = 40 // for example. Set your average height
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.reloadData()
}
I have a custom cell class called GameCell, the UI being created in storyboard. When my cells load, they load on top of each other. This problems occurs for cell.clipsToBounds YES and NO, just in different variations:
I have also tried [cell setClipsToBounds:(BOOL)] with no success.
Here's my cellForRowAtIndexPath method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"gameCell";
GameCell *cell = (GameCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
[cell.contentView.superview setClipsToBounds:NO];
NSLog(#"made a cell");
PFObject *myPartners = [self.games objectAtIndex:indexPath.row];
PFUser *partner = [self.partnerList objectAtIndex:indexPath.row];
// Cell profile image
cell.profileImage.layer.cornerRadius = cell.profileImage.frame.size.width / 2;
cell.profileImage.clipsToBounds = YES;
if([partner objectForKey:#"profilePic"]!=nil){
cell.profileImage.image = [partner objectForKey:#"profilePic"];
}
else {
cell.profileImage.image = [UIImage imageNamed:#"smile_green.png"];
}
//Cell indicators
if((int)[myPartners objectForKey:#"sent"]==1){
cell.myIndicator.image = [UIImage imageNamed:#"arrow_icon_dbl.png"];
}
else if ([myPartners objectForKey:#"sent"]==0){
cell.myIndicator.image = [UIImage imageNamed:#"arrow_icon.png"];
}
cell.partnerName.text = [myPartners objectForKey:#"receiverName"];
cell.gameId = myPartners.objectId;
// Cell drop shadow
[cell.cellView.layer setShadowColor:[UIColor blackColor].CGColor];
[cell.cellView.layer setShadowOpacity:0.5];
[cell.cellView.layer setShadowRadius:2.0];
[cell.cellView.layer setShadowOffset:CGSizeMake(1.0, 1.0)];
// Cell buttons
if([myPartners objectForKey:#"picture"]!=nil) {
[cell.myPlay setEnabled:NO];
} else {
[cell.myPlay setEnabled:YES];
}
return cell;
}
The view is a UITableViewController embedded in a NavigationController
You have used dequeueReusableCellWithIdentifier:
use like 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];
}
and also check this link.
UITableView cell Contents are disappearing and overlapping when scrolled in UITableViewcell?
You should make sure that the height of your cell is the RowHeight of your UITableView control.
e.g.,
Cell is designed from XIB, and the height of the view is 30, then make sure:
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 30.0f;
}
In attributes inspector cancel Adjust Scroll view insets option.
you need clicked view controller .
I have a TableViewController that initialize my cell:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
FIDPostTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell for this indexPath
[cell updateFonts];
[cell loadDataWithPost:[self.posts objectAtIndex:indexPath.item]];
cell.parentTableViewController = self;
cell.indexPath = indexPath;
[cell draw];
if(self.selectedIndex == indexPath.row){
//Do expand cell stuff
} else{
//DO closed cell stuff
}
return cell;
}
and that responds to heightForRowAtIndexPath:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *reuseIdentifier = CellIdentifier;
FIDPostTableViewCell *cell = [self.offscreenCells objectForKey:reuseIdentifier];
if (!cell) {
cell = [[FIDPostTableViewCell alloc] init];
[self.offscreenCells setObject:cell forKey:reuseIdentifier];
}
// Configure the cell for this indexPath
[cell updateFonts];
[cell loadDataForHeightCalculationWithPost:[self.posts objectAtIndex:indexPath.item]];
[cell draw];
if(self.selectedIndex == indexPath.row){
return [cell calculateHeight] + 100;
} else{
return [cell calculateHeight];
}
}
self.selectedIndex is a int local variable of TableViewController
Each custom cell have inside a button, that respond to a selector when touched, this is my CustomViewCell code:
self.expandSocialAction = [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.expandSocialAction.backgroundColor = [FIDUIHelper fideniaLightBlue];
[self.expandSocialAction addTarget:self action:#selector(selectRow:) forControlEvents:UIControlEventTouchUpInside];
[self.contentView addSubview:self.expandSocialAction];
and then:
-(void)selectRow:(id)sender{
if(self.parentTableViewController.selectedIndex == self.indexPath.row){
self.parentTableViewController.selectedIndex = -1;
} else{
self.parentTableViewController.selectedIndex = self.indexPath.row;
}
[self.parentTableViewController.tableView beginUpdates];
[self.parentTableViewController.tableView endUpdates];
}
The cell have a pointer to parent tableViewContorller: self.parentTableViewController.
All work fine, after beginUpdate and endUpdates call, the method heightForRowAtIndexPath is called ( i put a break point in ) and also che cell have the right height.
If i click the button on the first or second row the cell animate and change height fine, but if i scroll down the table and for example i click on the 6th row, the height change but the tableView scroll automatically to the first or second element.
Any suggestion?
Regards,
I have a feeling that the heightForRowAtIndexPath: method is part of the problem. Instead of performing the calculation, try to just use two constants in that method: one for expanded, one for collapsed. I'm wondering if the method is taking too long to execute and then thinks the height of the rows are 0, then the calculation finally returns, but the UITableView scroll position is not updated.
Another suggestion might be that your estimatedHeight and heightFor methods are returning two vastly different values.
check if you have used ScrollTORowAtIndexPAth someWhere in your code
I was trying to find solution almost everywhere, but I didn't find it. So, here is my problem.
I have UITableView with custom UITableViewCells.
The first cell has UIScrollView inside its Content View.
The Second cell has UILables and other basic views inside its Content View.
So, if there is UIScrollView inside the first cell, content of the second cell disappears. It appears only if the first cell scrolls out of the tableView frame.
Can anybody help me figure it out? Thank you.
Code preview
#pragma mark - UITableView Data Source
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if ([indexPath isEqual:_photosIndexPath]) {
static NSString *PhotosCellIdentifier = #"AdDetailsPhotosCell";
BazarAdDetailPhotosCell *cell = [tableView dequeueReusableCellWithIdentifier:PhotosCellIdentifier];
if (!cell) {
cell = [[BazarAdDetailPhotosCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:PhotosCellIdentifier];
}
cell.photoScrollView.scrollsToTop = NO;
cell.photoScrollView.delegate = cell;
[cell setPhotos:_adDetail.photos];
return cell;
}
else if ([indexPath isEqual:_adDetailsPath]) {
static NSString *DetailsCellIdentifier = #"AdDetailsDetailCell";
BazarAdDetailsDetailCell *cell = [tableView dequeueReusableCellWithIdentifier:DetailsCellIdentifier];
if (!cell) {
cell = [[BazarAdDetailsDetailCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:DetailsCellIdentifier];
}
cell.adTitleLabel.text = _adDetail.title;
cell.priceLabel.text = _adDetail.price;
// this cell content disappears
}
}
Might be issue with cell drawing on iOS 7.1, according answer on iOS 7.1 beta5 tableviewcell height showing objects outside it's range, try to clip subviews:
cell.clipsToBounds = YES;
Try it
#pragma mark - UITableView Data Source
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if ([indexPath isEqual:_photosIndexPath])
{
static NSString *PhotosCellIdentifier = #"AdDetailsPhotosCell";
BazarAdDetailPhotosCell *cell = [tableView dequeueReusableCellWithIdentifier:PhotosCellIdentifier];
if (!cell) {
cell = [[BazarAdDetailPhotosCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:PhotosCellIdentifier];
}
cell.photoScrollView.scrollsToTop = NO;
cell.photoScrollView.delegate = cell;
[cell setPhotos:_adDetail.photos];
return cell;
}
else {
static NSString *DetailsCellIdentifier = #"AdDetailsDetailCell";
BazarAdDetailsDetailCell *cell = [tableView dequeueReusableCellWithIdentifier:DetailsCellIdentifier];
if (!cell) {
cell = [[BazarAdDetailsDetailCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:DetailsCellIdentifier];
}
cell.adTitleLabel.text = _adDetail.title;
cell.priceLabel.text = _adDetail.price;
// this cell content disappears
return cell;
}
}
I created several cells with Interface Builder, and I'm using them to fill a UITableView. In other words, I have 3 classes for 3 different kinds of cell, and an other view which contains a UITableView.
- My UITableView containing different kinds of cells :
Here's my problem :
On the iPhone emulator, it looks great. But on the iPad emulator, the custom cells width is fixed. The UITableView width fits to the screen width, so it's good, but the UITableViewCells does not fit to the UITableView. I want to force the custom UITableViewCells to take the UITableView width.
Is there anything to do in - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPathmethod, where I instanciate my custom cells ?
Or do I have to write a thing like self.fitToParent; in the custom cells header file ?
EDIT (schema) :
EDIT 2 (cellForRowAtIndexPath method) :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifierType1 = #"cellType1";
static NSString *cellIdentifierType2 = #"cellType2";
NSString *currentObjectId = [[myTab objectAtIndex:indexPath.row] type];
// Cell type 1
if ([currentObjectId isEqualToString:type1])
{
CelluleType1 *celluleType1 = (CelluleType1 *)[tableView dequeueReusableCellWithIdentifier:cellIdentifierType1];
if(celluleType1 == nil)
celluleType1 = [[CelluleType1 alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifierType1];
celluleType1.lblAuteur.text = #"Type1";
return celluleType1;
}
// Cell type 2
else if ([currentObjectId isEqualToString:type2])
{
CelluleType2 *celluleType2 = (CelluleType2 *)[tableViewdequeueReusableCellWithIdentifier:cellIdentifierType2];
if(celluleType2 == nil)
celluleType2 = [[CelluleType2 alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifierType2];
celluleType2.lblAuteur.text = #"Type2";
return celluleType2;
}
else
return nil;
}
}
I think uitableviewcell's width is the same as the tableview's width.You can try to set cell's background color to test it. cell.backgroundColor = [UIColor redColor] ;
You should create a class which inherit from UITableViewCell and override it's method - (void)layoutSubviews , adjust your content's frame there.
I resolved my problem using the following code in each custom cell class. It's not very clean, but I can't spend one more day on this issue...
- (void)layoutSubviews
{
CGRect contentViewFrame = self.contentView.frame;
contentViewFrame.size.width = myTableView.bounds.size.width;
self.contentView.frame = contentViewFrame;
}
Thank you for your help KudoCC.
- (void)awakeFromNib {
[super awakeFromNib];
// anything you write in this section is taken with respect to default frame of width 320.
}
awakeFromNib is called when [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; is processed- anything you write in section is taken with respect to default frame of width 320.
You need to make another custom function and call it after cell gets initialized.
For eg:-
#implementation CheckinTableViewCell{
UILabel *NameLabel;
UILabel *rollLabel;
}
- (void)awakeFromNib {
[super awakeFromNib];
NameLabel = [[UILabel alloc] initWithFrame:CGRectZero];
rollLabel = [[UILabel alloc] initWithFrame:CGRectZero];
[self.contentView addSubview:NameLabel];
[self.contentView addSubview:rollLabel];
}
-(void) bindView{
NameLabel.frame = CGRectMake(10, 10, self.contentView.frame.size.width-20, 20);
rollLabel.frame = CGRectMake(10, 30, NameLabel.frame.size.width, 20);
}
and call this function in tableview cellForRowAtIndex:-
-(UITableViewCell*) tableView: (UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Cell";
CheckinTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if(cell ==nil){
cell = [[CheckinTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.name = #"Harry";
cell.rollno = #"123456";
[cell bindView];
return cell;
}