I have a tableview where cells are populated from the xib files. There are 2 cell xib files displaying different content in the tableview dynamically.
I want to set the row height for the tableview based on which cell is being populated. I used heightForRowAtIndexPath to set the height of the row depending on the cell xib. Following is the code:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
CommentBoxCell *commentBoxCell;
UserCommentCell *userCommentCell;
if ([commentsAndTagsArray count]) {
if (!commentBoxCell){
return commentBoxCell.bounds.size.height;
}
if (!userCommentCell){
return userCommentCell.bounds.size.height;
}
}
//default height of the cell
return 44;
}
Doing this displays nothing in the tableview, just empty cells. Without the heightForRowAtIndexPath, the cells are populated with correct content but with default tableview row height.
How can I set the row height in tableview whose cells are populated from the xib files?
it looks like commentsAndTagsArray does is not nill and have 1 or more objects so it enter the first if, after that it does nothing as your cell's aren't initialized and there's not default return there.
Now heightForRowAtIndexPath: comes before cellForRowAtIndexPath: so you don't have a cell yet at this point, but you should be able to know what kind of cell do you want to present using the indexPath or whatever logic you're using to identify which cell type to create, why don't you use that logic to select the height instead?
You should first instantiate your 2 cells like this somewhere in your viewDidLoad method:
commonetBoxCell = [[[NSBundle mainBundle] loadNibNamed:#"CommentBoxCellNib" owner:self options:nil] firstObject];
userCommentCell = [[[NSBundle mainBundle] loadNibNamed:#"UserCommentCellNib" owner:self options:nil] firstObject];
Then, you should update the height method like this:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
CGFloat height = 44.0;
if (<this is a comment box cell>) {
[commonetBoxCell updateWithData];
height = [commonetBoxCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
}
if (<this is a user comment cell>) {
[userCommentCell updateWithData];
height = [userCommentCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
}
return height;
}
Related
We can get a cell from:
UITableViewCell * cell = [self tableView:tableVie cellForRowAtIndexPath:indexPath]
but it will calling the method cellForRowAtIndexPath:
if I know the cell's tag or indexPath , it's there a way to get the specified cell without to calling cellForRowAtIndexPath:?
Add some reason why I can't call cellForRowAtIndexPath:indexPath
I want to get the cell in the method cellForHeightAtIndexPath to reset the height of each cell. :
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell * cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
CommentsListResponseDataModel * model = self.liveCommentData[indexPath.row -1];
if (model.viewHeight > 0) {
return model.viewHeight;
} else {
if (model.parentComment) {
CommentParentCell * cc = (CommentParentCell *)cell;
return cc.viewHeight;
} else {
CommentSingleCell * cc = (CommentSingleCell *)cell;
return cc.viewHeight;
}
}
}
}
But this will become a dead loop because it all cellForRowAtIndexPath:indexPath and cellForRowAtIndexPath:indexPath will recall cellForHeightAtIndexPath:indexPath
As of my understanding, you are trying to get the cell object by calling UITableView datasource method. But when you try to do like that then it will be infinite loop call and you will never get the cell object. So in order to get cell object from UITableView, do the following steps.
Declare your UITableView as global to the your ViewController, something like UITableView *_tableView; or #IBOutlet weak UITableView *_tableView;
Then try to call the
//specify the item indexpath
NSIndexPath *_indexPath = [NSIndexPath indexPathForItem:3 inSection:1];
//now try to access cell object by passing cell indexPath
UITableViewCell *_cell = [_tableView cellForRowAtIndexPath:_indexPath];
It seems you want something unrelated to your original question - you want your table view cells to size automatically, depending on content.
What you need to do is:
1. add constraints to your cell - make sure it doesn't have a height constraint, but its content must have Top and Bottom constraints.
2. remove heightForRowAtIndexPath as it will not be necessary
3. set your table view row height to automatic
tableView.rowHeight = UITableViewAutomaticDimension
Now just setup your cell - resize its content to desired height and table cell will automatically be resized
I have two custom UITableViewCell in my table view, that I can't resize properly. The problem is that in IB there is a row height option for the table view, that sets the same height for both cells. I can't just edit the height of the cells in IB, somewhy it doesn't works, the table view's row height overwrites it. I'm using static heights so I tried to set it based on the cell's type, but can't make it work. Is it possible that just my if statement is wrong or I done the whole thing wrong?
- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *) indexPath {
InboxCellTableViewCell *cellMessage = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
InboxCell2TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell2" forIndexPath:indexPath];
if(cell) {
[cellMessage layoutIfNeeded];
return 200;
} else {
[cell layoutIfNeeded];
return 155;
}
}
You definitely can do this, and you will do it in -heightForRowAtIndexPath as you suspect.
Instead of attempting to load the cell as you are doing, you should instead use the IndexPath to determine what type of cell is there and then return the proper height for that cell type.
In your cellForRowAtIndexPath method you must have some logic that is already determining the cell type for a given IndexPath, as you return a varying type of Cell from that method already? That same logic can be used to return the appropriate height in the heightForRowAtIndexPath method.
I am trying to create a sample app to resize a cell. The cell is staying at the default height of 44px. I am unable to make this change through the storyboard because I have a view with varying height inside the cell. Can this be done with only 1 cell? I have an outlet from the table cell to the variable called cell. My code in the .m file is as follows. Also, all the cells are already static.
self.whereCell.frame = CGRectMake(0, 191, 320, 78);
Have you tried the tableView:heightForRowAtIndexPath: method?
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == 0) {
return 191;
}
return 44;
}
This shouldn't been needed if the cell is static though; you should be able to set the height of the cell in Interface Builder.
I created a TableView with Expandable cell as shown here. In my case the expanded area contains a TextView. My view contains a tag (as label text) and its' meaning (in text view). And things are working fine.
I have come up with a situation where a single tag can have multiple meanings. So I need to show all the meanings. So I got to have that many textview's as many meanings for each tag.
I have added a TableView (with TextView in TableCell) inside the expandable part of the table cell. So can add X number of rows in the expanded table cell with each meaning of the tag in single cell. I want to set the height of TextView, TableView and finally TableViewCell. I tried different ways, but am not able to achieve it. Can you help me achieve it the way I am looking for.
Screen shot of something that I am trying to achieve -
UPDATE :-
My cellForRowAtIndexPath method where I am trying to set properties :-
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"Table View TAG = %d ROW = %d", tableView.tag, indexPath.row);
// TABLE VIEW IN THE CELL
if (tableView.tag == 10) { // cell.valuesTv
CannedValueCell *ccell = (CannedValueCell *) [tableView dequeueReusableCellWithIdentifier:#"cannedValueCell"];
if (ccell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CannedValueCell" owner:self options:nil];
ccell = [nib objectAtIndex:0];
}
// Populate valuesTv
ccell.valueTextView.text = [valuesArray objectAtIndex:indexPath.row];
UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(valueTextViewTapped)];
[ccell.valueTextView addGestureRecognizer:gestureRecognizer];
//[ccell.valueTextView sizeToFit]; // Makes no difference
// CGRect frame = ccell.valueTextView.frame;
// frame.size.height = ccell.valueTextView.contentSize.height;
// ccell.valueTextView.frame = frame;
NSLog(#"*** TEXTView HEIGHT = %f C_CELL HEIGHT = %f ** TV HEIGHT = %f", ccell.valueTextView.frame.size.height, ccell.frame.size.height, cell.valuesTv.frame.size.height );
// *** TEXTView HEIGHT = 79.000000 C_CELL HEIGHT = 80.000000 ** TV HEIGHT = 80.000000
// AS SET HEIGHT IN STORY BOARD - NO DIFFERENCE
return ccell;
} else {
// MAIN TABLE VIEW
static NSString *cellIdentifier = #"CannedCell";
cell = (CannedCell *) [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if(cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CannedCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
// Set datasource and delegate for the cell's TableView
cell.valuesTv.dataSource = self;
cell.valuesTv.delegate = self;
.......
}
}
Table view delegate method
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (tableView == self.cannedTV) {
if (selectedIndex == indexPath.row)
return 150; //(30 + (80 * valuesArray.count));
else
return 30;
}
return 30;
}
}
This is what the result is :-
I tried various things, searched a lot on net, but couldn't find solution for the following :-
Set height of Text View as much as the contents of it.
The inner table should be completely visible - in all cells full textview should be visible with its complete contents properly. So each cell may have different height.
Thus the outer/main table expandable cell should also be accordingly set. - For this I tried (30 + (80 * valuesArray.count));, but the inner table doesn't occupy that much space.
How to get which textview is tapped ? When textview is tapped, the method valueTextViewTapped is fired, but yet am not able to find which textview is tapped on. How can I pass the indexPath.row to valueTextViewTapped method, so can find which textview was tapped on ??
Can you please guide me set the height of the components accordingly and achieve the requirements. Any help is highly appreciated. Thanks.
A table view and table view controller are very powerful tools.
Based on the information provided, your suggested implementation is satisfactory.
A UITableViewCell can have its height set dynamically using the table view delegate method heightForRowAtIndexPath.
You can respond to a user selecting the UITableViewCell using the table view delegate method didSelectRowAtIndexPath.
I am trying to resize my UITableViewCell's frame via:
[cell setFrame:CGRectMake(cell.frame.origin.x,
cell.frame.origin.y,
cell.frame.size.width,
cell.frame.size.height+25)];
however, it's not resizing after I do this... why is this?
This is weird as if I add a UIToolBar into the cell, it resizes but when I am adding a UIView, it doesn't:
[cell.contentView addSubview:sideSwipeView];
Here's the long and short of it:
Your cell width is determined by the width of the tableview it's in.
[EDIT: If it's a grouped table view, the cell is 20 - 60 pixels narrower than the tableview width, depending if you're using an iPhone, or an iPad.]
Your cell height is determined by the heightForRowAtIndexPath method.
If you're manually setting the cell's frame, it's going to be useless except when you're using a subclassed cell where you want to add subviews based on the cell's dimensions.
Even in this case, it's recommended to get the cell's frame from the tableview by using rectForRowAtIndexPath:(NSIndexPath*)indexPath method and then setting that frame as the cell's frame (after setting the frame's origin Y as 0).
I'm not quite sure about the UIToolBar, but your subview's frame won't change on changing the cell frame.
Maybe if you could tell us what you're trying to achieve, we can suggest a solution for you?
--------------------EDIT--------------------
So you need to dynamically add a subview to a cell on tapping it and resize it's height according to the new subview. This is gonna get hairy so here goes:
In your .h file declare:
BOOL subviewAdded;
In your .m file, in the init, do:
subviewAdded = NO;
Let's assume that you want the cell's height to be 50 without the subview and 100 with the subview. Accordingly, your heightForRow method should be:
- (CGFloat)tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return (subviewAdded?100.0f:50.0f);
}
This means that initially since subviewAdded is NO, all your cells will have the smaller height.
Now, to add a subview to a cell on tapping it, and to change it's height dynamically, do this in your didSelectRow method:
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//Get the cell at this indexPath
UITableViewCell *thisCell = [tableView cellForRowAtIndexPath:indexPath];
if(subviewAdded)
{
subviewAdded = NO;
for(int i = 0; i < [thisCell.contentView.subviews count]; i++)
{
UIView *thisSubview = [thisCell.contentView.subviews objectAtIndex:i];
[thisSubview removeFromSuperview];
}
}
else
{
UIView *someView = [[UIView alloc] initWithFrame:someFrame];
[thisCell.contentView addSubview:someView];
[someView release];
subviewAdded = YES;
}
NSMutableArray *array = [NSMutableArray array];
[array addObject:indexPath];
[tableView reloadRowsAtIndexPaths:array
withRowAnimation:UITableViewRowAnimationFade];
}
So what's going to happen here is you're adding a subview to this cell you've tapped. Reloading this cell will call heightForRowAtIndexPath and do a nice little fade animation and change your tableview heights.
IMPORTANT: Ideally, you should maintain an array of NSNumbers with boolean values. The array size should be the same size as the number of tableview cells you have.
In heightForRow, you would then check against this array instead of using a single boolean for the whole tableView. This would ensure that you could have different heights for different cells.
That would look something like:
- (CGFloat)tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath {
BOOL thisBool = (BOOL)[[booleanArray objectAtIndex:indexPath.row] boolValue];
return (thisBool?100.0f:50.0f);
}
I didn't post all that code here since it's implied and what I've posted should put you well on your way to doing the boolean array thing.
Anyway, there you are. I just tested this code myself so it works :)
If you want to increase the height of your cell based on some parameter eg. text, image,
you must implement the heightForRowAtIndexPath method of UITableViewDelegate in your code.
- (CGFloat)tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath