I am creating a cell:
-(AnswerTableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
AnswerTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[AnswerTableViewCell alloc] initWithFrame:CGRectMake(0, 0, self.answersTable.frame.size.width, [self tableView:nil heightForRowAtIndexPath:indexPath])];
}
NSLog(#"cell.frame - %#", NSStringFromCGRect(cell.frame));
NSLog(#"self.answersTable.frame - %#", NSStringFromCGRect(self.answersTable.frame));
AnswerObject* answer = self.question.answers[indexPath.row];
CGFloat height = [self tableView:nil heightForRowAtIndexPath:indexPath];
[cell setupAnswerTableViewCell:self.question answer:answer row:indexPath.row height:height];
return cell;
}
I see only a half of it.
When I print the cell and the table frames, I can see that the table is thiner then the cell. How did it happened?
2014-03-20 21:36:22.478 Theory[43601:60b] cell.frame - {{0, 0}, {320, 44}}
2014-03-20 21:36:22.479 Theory[43601:60b] self.answersTable.frame - {{20, 38.880001068115234}, {280, 500}}
You should create your cell using this initializer
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
This is the usual init in cells, so you do not need frame.
// You need to get the cell height from the answer text and return it in this method as CGFloat (Something like this example)
-(CGFloat)getAnswerHeightForCell:(Aswer *)answer {
NSString *text = answer.text;
CGSize textSize = [text sizeWithFont:[UIFont systemFontOfSize:14.0f] constrainedToSize:CGSizeMake(self.tableView.frame.size.width - PADDING * 3, 1000.0f)];
return textSize.height ;
}
In your dataSource and delegate methods of the tableView you need to add the height of the cell and create the cell.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
Answerobject * answer = [self.question.answers[indexPath.row];
CGFloat answeSize = [self getAnswerHeightForCell:answer ];
return textSize.height + SOME_EXTRA_HEIGHT_FOR_PADDING;
}
-(AnswerTableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
AnswerTableViewCell *cell =( AnswerTableViewCell*) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[LZCommentCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] ;
}
AnswerObject* answer = self.question.answers[indexPath.row];
[cell setupAnswerTableViewCell:self.question answer:answer row:indexPath.row];
return cell;
}
It's probably not the tableViewCell that has the wrong frame, but the tableview. In case of UITableView, its rows will always have the same width as the tableView itlself.
BTW you really should not use initWithFrame:reuseIdentifier: since it's deprecated. (And especially not nitWithFrame: method, how will your cell know about its reuseIdentifer?) You should use initWithStyle:reuseIdentifier: instead if you are creating your cells programmatically.
Also calling
[self tableView:nil heightForRowAtIndexPath:indexPath]
in tableView:cellForRowAtIndexPath is very wrong. If you pass tableView in the parameter it will cause an infinite loop, that's probably the reason why you are passing nil. You can extract the code in your tableView:heightForRowAtIndexPath into a separate method and call in both cases. But you really should trust your cell to adjust the layout of its content based on its height, so you really should not deal with cell frame in tableView:cellForRowAtIndexPath method.
Related
Most of the time, when my app is working the way it should, my Table View items look like this:
But every so often a cell (on initial load) looks likes this:
As you can see the image has resized, the 'published By' label has resized.
Why would this happen? The same code/storyboard should affect all the cells the same way? Why are some not doing what they are told?
If it helps, when a cell loads the wrong way, all I have to do is scroll up, and back down again, and the problem is fixed !!
This means that there clearly isn't a problem with the image or the amount of text, is it just the iPhone acting up?
Thanks for any help !
I think its cell dequeue issue. Your cell could not calculate proper height for cell. If you are using autolayout try the following code. hope it will works for you.
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
static YOUR_TABLEVIEW_CELL *sizingCell = nil;
static NSString *CellIdentifier=#"YOUR_TABLEVIEW_CELL_IDENTIFIER";
sizingCell =[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (sizingCell==nil)
{
sizingCell=[[YOUR_TABLEVIEW_CELL alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
[self configureFareIssueCell:sizingCell atIndexPath:indexPath];
return [self calculateHeightForConfiguredSizingCell:sizingCell];
}
//assign all the lables & images here
- (void)configureFareIssueCell:(YOUR_TABLEVIEW_CELL* )cell atIndexPath:(NSIndexPath *)indexPath
{
//e.g
cell.lbl.text=#"YOUR_TEXT";
cell.imageView.image=[UIImage imageNamed:#"NAME_OF_YOUR_IMAGE"];
}
- (CGFloat)calculateHeightForConfiguredSizingCell:(YOUR_TABLEVIEW_CELL *)sizingCell
{
CGSize size = [sizingCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
return size.height + 1.0f; // Add 1.0f for the cell separator height
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier=#"YOUR_TABLEVIEW_CELL_IDENTIFIER";
YOUR_TABLEVIEW_CELL *cell =[tableView dequeueReusableCellWithIdentifier:#"YOUR_TABLEVIEW_CELL_IDENTIFIER"];
if (cell==nil)
{
cell=[[YOUR_TABLEVIEW_CELL alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
[self configureFareIssueCell:cell atIndexPath:indexPath];
return cell;
}
Do you use layer mask for creating rounded image? If yes, you see this strange behavior because layer mask was created before UITableView assign proper frame for cell, so layer mask will have incorrect frame.
I am setting the width and height of UITableViewCell in the delegate methods but the when i check the cell frame in cellForRowAtIndexPath method then its totally different. Below is my Code. I am doing every thing programatically.
self.myTable = [[UITableView alloc] initWithFrame:CGRectMake(self.view.frame.size.width * 0.05,self.view.frame.size.height * 0.08,self.view.frame.size.width * 0.90,
(self.view.frame.size.height * 0.90) - tabBarHeight ) style:UITableViewStylePlain];
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1.0;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return 5;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
if(indexPath.row == 0 || indexPath.row == 4){
return self.myTable.frame.size.height * 0.08;
}
return (self.myTable.frame.size.height * 0.28);
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if(!cell){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
if(indexPath.row != 4){
cell.userInteractionEnabled = NO;
}
switch (indexPath.row) {
case 0:{
NSLog(#"0th cell Frame : %#", NSStringFromCGRect(cell.frame));
break;
}
case 1:{
NSLog(#"1st cell Frame : %#", NSStringFromCGRect(cell.frame));
break;
}
case 2:{
NSLog(#"2nd cell Frame : %#", NSStringFromCGRect(cell.frame));
break;
}
case 3:{
NSLog(#"3rd cell Frame : %#", NSStringFromCGRect(cell.frame));
break;
}
case 4:{
NSLog(#"4rth cell Frame : %#", NSStringFromCGRect(cell.frame));
break;
}
default:
break;
}
return cell;
}
The output for the cell frame i am getting is {{0, 0}, {320, 44}}. But this cell frame is not correct. The Height should be 129 and the width should be something like 288. Can some one guide me what i am doing wrong here?
However, if you still need your given (predefined) size for your cell, you can always use,
For width,
With case of a custom cell, you can make a method like this,
- (CGFloat)cellWidth {
return [UIScreen mainScreen].bounds.size.width;
}
Without custom cell, you can always make a function within the same class where you're creating the UITableView,
- (CGFloat)cellWidth {
return yourTableView.frame.size.width;
}
which will return exact size of your table cell. (I'm always prefer second method because sometime you just don't create device width cells!)
For height,
With case of custom cell, you can make a class method like this,
+(CGFloat)myCellHeight {
return 45.f;
}
Without custom cell, you can always make a function within the same class where you're creating the UITableView,
-(CGFloat)myCellHeight {
return 45.f;
}
which you can use in your UIViewController, with cell class name (for custom cell), [cellClassName myCellHeight] or [self myCellHeight] (default cell in UIViewController) in table's - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath datasource method.
These ways you'll have your cells exact width/height, whenever you want ! :)
Nothing, your code is ok. Your cells will have the size you want. The problem is your cells don't know them final size in this methods cellForRowAtIndexPath. In this methods they think, they have the default size. But before they appear they will be resized. If you define your cells by code, you need use de dimension you expect,this is the tableView width and the height of the methods (heightForCell or estimateHeightForCell). You can check this, by comment this line, and pressing in the delegate: (also you can see).
Line to comment to check:
....
if(indexPath.row != 4){
// cell.userInteractionEnabled = NO;
}
.....
Implement to check:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSLog(#"cell pressed Frame : %#", NSStringFromCGRect(cell.bounds));
}
- (void)viewDidLoad
{
self.myTable = [[UITableView alloc] initWithFrame:CGRectMake(self.view.frame.size.width * 0.05,self.view.frame.size.height * 0.08,self.view.frame.size.width * 0.90, // set the frame for your tableview
(self.view.frame.size.height * 0.90) - tabBarHeight ) style:UITableViewStylePlain];
self.myTable.delegate = self;
self.myTable.dataSource = self;
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
I have this UITableView, made in code ,and when i see it first time, the cells size that i read are wrong-hence the icons on the cells calculated wrong and are very small.
Than , when i start scrolling,every cell i scroll through ,its icons (on this cell),becomes bigger and get their right size,and i see also the small icons too, so i have for each cell a small icon and a big icon,where i should only have the big.
Why is that happens ? (this view also has some collection view inside it)
//tabel view
frm.origin.y=self.frame.size.height-openY;
tableView = [[UITableView alloc]initWithFrame:frm style:UITableViewStylePlain];
tableView.delegate=self;
tableView.dataSource=self;
[tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Cell"];
[self addSubview:tableView];
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [actionsMenus count];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return self.frame.size.height/5.0;
}
- (UITableViewCell *)tableView:(UITableView *)ttableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"Cell";
UITableViewCell *tcell= [ttableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
NSLog(#"%f", tcell.frame.size.height );
if (tcell == nil)
{
tcell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
NSString *kind=[actionsMenus objectAtIndex:indexPath.row];
NSString *icon=[NSString stringWithFormat:#"%#%d.png",kind,colorIndex];
//icon
UIImage *image=[UIImage imageNamed:icon];
UIImageView *view=[[UIImageView alloc] initWithFrame:CGRectMake(tcell.frame.size.width/2.0-0.8*tcell.frame.size.height/2.0, 0, 0.8*tcell.frame.size.height,0.8*tcell.frame.size.height)];
view.image=image;
[tcell addSubview:view];
return tcell;
}
If you're creating the table in viewDidLoad, I think the UITableView delegate methods are being called before the view's auto-layout is complete; so setting the heightForRowAtIndexPath: to
return self.frame.size.height/5.0;
uses the frame of the view pre-auto-layout to calculate the row height. If you absolutely need heightForRowAtIndexPath: to be dependent on the view's height though, perhaps add the table as a subview after view's layout is complete. For example, instead of adding it in your viewDidLoad, add it in viewDidLayoutSubviews, ex:
- (void) viewDidLayoutSubviews {
//table view
frm.origin.y=self.frame.size.height-openY;
tableView = [[UITableView alloc]initWithFrame:frm style:UITableViewStylePlain];
tableView.delegate=self;
tableView.dataSource=self;
[tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Cell"];
[self addSubview:tableView];
}
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.
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;
}