I am trying to use PXListView to show a table of cells containing NSTextFields and I want to vary the height of each cell to fix the text within it.
On my subclassed cell view I have a height method that calculates the height the cell should be:
- (CGFloat)height{
NSRect textRect = [self.text.attributedStringValue
boundingRectWithSize:NSMakeSize(NSWidth(self.text.frame), 0.0f)
options:NSStringDrawingUsesLineFragmentOrigin];
return MAX(90.0f, NSHeight(textRect)+73.0f);
}
Then on my PXListViewDelegate's heightOfRow method I get the cell for the row then get the height of that cell:
- (CGFloat)listView:(PXListView *)listView heightOfRow:(NSUInteger)row{
CustomViewCell *cell = (CustomViewCell *)[listView cellForRowAtIndex:row];
return [cell height];
}
The problem is that cell is always null, I believe this is because I have a chicken or the egg scenario. The cell is null because cellForRow is never called because the height is zero so no cell need to be loaded.
What is the correct way to vary the height of a PXListView cell based on the text within it?
My solution was to use the width of the table view to calculate the height of each table cell:
- (CGFloat)listView:(PXListView *)listView heightOfRow:(NSUInteger)row{
NSRect textRect = [self.text.attributedStringValue
boundingRectWithSize:NSMakeSize(NSWidth(self.tableView.frame), 0.0f)
options:NSStringDrawingUsesLineFragmentOrigin];
return MAX(90.0f, NSHeight(textRect)+73.0f);
}
Related
I would like to get the cell frame at tableView:cellForRowAtIndexPath: in order to position and size the views that I want to add to UITableViewCell's contentView. But there self.frame is always (0, 0, 320, 44).
I know you can get the right frame in layoutSubviews (thanks to this answer), but if I add the subviews there it would be done every time the cell is reused, not only once like in the "official" example at Programmatically Adding Subviews to a Cell’s Content View.
In that example they add some views using hardcoded frames like:
mainLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, 220.0, 15.0)];
I guess that example is outdated, since they should use constraints, or at least calculate the size of subviews using the actual cell frame (which may be impossible to get at that point indeed).
Note: this reminds me of the view holder design pattern used in Android.
This should return the bounding frame.
CGRect cellFrame = cell.bounds;
Then you can use it like
cellFrame.size.width;
cellFrame.size.height;
cellFrame.origin.x;
cellFrame.origin.y;
etc... Though origin.x and origin.y should be 0 each.
Maybe you should calculate cell height in a UITableViewCell subclass and use
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
in your delegate to find the correct height.
I use two solutions:
1) When I set the frames explicitly
I fake the frame:
#define SCREEN_WIDTH ([UIScreen mainScreen].bounds.size.width)
// Use whatever height you like for your cell
// Should be the same value you return in tableView:heightForRowAtIndexPath:
CGFloat cellHeight = XXX;
CGRect frame = CGRectMake(0, 0, SCREEN_WIDTH, cellHeight);
2) When I use autolayout
I just add my views and constraints to self.contentView.
[someView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.contentView addSubview:someView];
[self.contentView addConstraints:someConstraints];
But check this answer just in case.
I download Json data and then I populate my custom UITableView, the problem is that even if I calculate the height of the tableview based on the amount of elements I download the cells doesn't fit the whole height of the tableview, So my final situation is a tableview with n elements that has height of n*100 but the cells just fits a part of it.
This is the code I used to calculate the height:
//callback that contains the items I download
-(void)productsDownloaded:(NSArray *)items
{
_productsDetails = items;
CGFloat height = 100;
height *= items.count;
CGRect tableFrame = _customTableView.frame;
tableFrame.size.height = height;
_customTableView.frame = tableFrame;
[_customTableView reloadData];
}
I also tried:
_customTableView.alwaysBounceVertical = NO;
_customTableView.scrollEnabled = NO;
But with no results.. How can I tell the cells to fit the height of the cell?
To achieve a scrollable table view, you have to use the tableView:heightForRowAtIndexPath: delegate method to specify the size (height) or your cell, not just change the frame of your table view.
Example:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
//TODO: Calculate cell height
return 60.0f;
}
To have all the cells visible on one screen, the total height of the table view cells has to be equal to the height of the table view, thus the height of one table view cell should be:
CGFloat cellHeight = CGRectGetHeight(tableView.frame) / numberOfCells;
However, I really don't understand why you would want to do this. The whole reason of a table view is to have a fixed height for cells and scroll (Like the Settings app does it).
On the iPad, the Grouped style tableview's cells are inset deeper from the edge of the tableview than on the iPhone.
I need to retrieve the Left and Right distances from the edges of the tableview to where the cell begins. What i'm referring to is similar to "Margins". I read the UITableview API up and down and can't find a property that returns this.
I need to use this in calculation to compute where to position content in my cells.
Thanks in advance!
Alex
I haven't tested this but i'm pretty sure you should just be able to pick up the frame of both and then compare from there.
CGRect cellFrame = yourCell.frame;
CGRect tableFrame = yourUITableView.frame;
The CGRect values are (x coordinate, y coordinate, width, height).
Also you can just print out the frames using :
NSLog(#"your cell frame is %#",NSStringFromCGRect(yourCell.frame);
NSLog(#"your table frame is %#",NSStringFromCGRect(yourUITableView.frame);
I solved this with overriding the layoutSubviews call for the iPad and setting the grouped view margins to what I want them to be, rather then what the apparently hidden value is. Other answers in Stack point out that it can vary from 10 to 45 pixels in width.
In your CustomTableViewCell class
- (void)layoutSubviews
{
CGRect f = self.bounds;
f = CGRectInset(f, 10, 0);
self.contentView.frame = f;
self.backgroundView.frame = f;
}
You could force it to keep contentView and backgroundView to be equal to that of the TableCell width which is that TableView width, but in this case I still wanted my grouped view to be inset a little bit. It also allows you to better match with a custom header/footer view which will go edge to edge without work.
I have a tableview, one of the rows contains a cell that contains a UITextView. I need to know the size of the textview because I need it to fit the cell and return that size in 'heightForRowAtIndexPath' method. Using the NSString method for size only works for labels, not for textviews. What are my options?
Thanks
Does the UITextView already have the proper size, or do you need to resize it as well to exactly contain its text? There are no out-of-the-box methods to do that I believe.
If it already has the proper size, you can just get the height from its frame:
CGRect frame = textView.frame;
CGSize size = frame.size;
CGFloat = size.height;
I'm trying to mimic the address cell in Address Book / Contacts App.
I want a cell with style UITableViewCellStyleValue2 to display an address such as:
// 123 Fake St.
// Suite 555
// Denver CO, 80000
But actual cell isn't drawing the way I want. The label is drawing outside the bounds of the tableview row and part of top of the label is being cut off by the row directly above it.
Here's what I have so far:
cell.detailTextLabel.lineBreakMode = UILineBreakModeWordWrap;
cell.autoresizingMask = UIViewAutoresizingFlexibleHeight; //doesn't seem to do anything
self.tableView.rowHeight = 88.0f; // default is 44.0
cell.detailTextLabel.numberOfLines = 0; //unlimited lines
An NSLog statement confirmed the rowHeight is set to 88.0.
I realize a delegate method exists to change the row height. However, in my current app I only need this one cell to expand with the text, so I didn't feel it necessary to implement the delegate method.
Thank you for your help.
I don't think that setting row height this way (self.tableView.rowHeight = 88.0f;) for a single row will work. You should implement the delegate method which in your case is very simple, i.e.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return ([indexPath row] == MY_TALLER_CELL_ROW) ? 88.0f : 44.0f;
}
I think you'll probably have more luck not using the cell's default textLabel and detailTextLabel views; instead, create your own labels and add them to the cell's content view.