The grouped UITableView places a margin between the edge of the view and the table cells. Annoyingly (for me) this margin is some function of the width of the view.
In my application I have two UITableViews of di开发者_C百科fferent widths that I am looking to align the cell edges of.
Is it possible to get this margin? Or better is it possible to set this margin?
cheers, --Ben
Grouped TableView Width in Relation to Cell Margin
TBWidth (0 to 20) Left Margin = TBWidth - 10
TBWidth (20 to 400) Left Margin = 10
TBWidth (401 to 546) Left Margin = 31
TBWidth (547 to 716) Left Margin = apx 6% of tableView
TBWidth (717 to 1024) Left Margin = 45
- (float) groupedCellMarginWithTableWidth:(float)tableViewWidth
{
float marginWidth;
if(tableViewWidth > 20)
{
if(tableViewWidth < 400)
{
marginWidth = 10;
}
else
{
marginWidth = MAX(31, MIN(45, tableViewWidth*0.06));
}
}
else
{
marginWidth = tableViewWidth - 10;
}
return marginWidth;
}
By creating (and using!) a subclass of UITableViewCell, you can possibly achieve what you're looking for. Just move the contentview and backgroundview around in layoutsubviews, as in the code sample below which shifts the visible parts of the cell 20pt to the right.
- (void) layoutSubviews
{
NSLog (@"Cell/contentview/backgroundview before:\n%@\n%@\n%@", self, self.contentView, self.backgroundView);
[super layoutSubviews];
CGRect frame = self.backgroundView.frame;
frame.origin.x += 20;
frame.size.width -= 20;
self.backgroundView.frame = frame;
frame = self.contentView.frame;
frame.origin.x += 20;
frame.size.width -= 20;
self.contentView.frame = frame;
NSLog (@"Cell/contentview/backgroundview after:\n%@\n%@\n%@", self, self.contentView, self.backgroundView);
}
I was using Matthew Thomas implementation but it's unreliable (it's broken if you use autorotation in your controllers) and has a lot of hardcoded code... I realized that there is a very simple solution, my implementation is a single line of code:
- (float)cellMargins
{
return self.backgroundView.frame.origin.x * 2;
}
This is far better IMO :)
EDIT: my implementation was unreliable too (it does not work properly when switching to/from editing mode), this is my final implementation (I handled right and left margins separately):
- (float)leftMargin
{
return self.contentView.frame.origin.x;
}
- (float)rightMargin
{
CGRect frame = self.contentView.frame;
float containerWidth = frame.size.width;
float margin = self.frame.size.width - (containerWidth + frame.origin.x);
return margin;
}
- (float)cellMargins
{
return ([self leftMargin] + [self rightMargin]);
}
Updated Matthew Thomas's code for cell margins calculation. Created via UITableView's category. This can be useful, when you need to determine text height in cell, and you dont' know width of that cell.
So, actual cell can be calculated like
cell.width = tableView.width - tableView.cellsMargin * 2;
An here's the code
@implementation UITableView (CellsMargins)
// This is black magic
// from
// http://stackoverflow.com/questions/4708085/how-to-determine-margin-of-a-grouped-uitableview-or-better-how-to-set-it
- (CGFloat)cellsMargin {
// No margins for plain table views
if (self.style == UITableViewStylePlain) {
return 0;
}
// iPhone always have 10 pixels margin
if (! isIPad()) {
return 10;
}
CGFloat tableWidth = self.frame.size.width;
// Really small table
if (tableWidth <= 20) {
return tableWidth - 10;
}
// Average table size
if (tableWidth < 400) {
return 10;
}
// Big tables have complex margin's logic
// Around 6% of table width,
// 31 <= tableWidth * 0.06 <= 45
CGFloat marginWidth = tableWidth * 0.06;
marginWidth = MAX(31, MIN(45, marginWidth));
return marginWidth;
}
@end
This is now accessible through a property of UITableViewCell:
@property(nonatomic) UIEdgeInsets separatorInset
Apple Docs - UITableViewCell - seperatorInset
More accurate left margin for the 'stretchy' zone instead of the 'apx. 6% calc.'
Side note: the iPad implements additional section top and bottom padding in addition to the left margin padding, it's 10.0f below 400.0f table width and 31.0f otherwise.
-(CGFloat)leftMarginForTableView:(UITableView*)tableView
{
if (tableView.style != UITableViewStyleGrouped) return 0;
CGFloat widthTable = tableView.bounds.size.width;
if (isPhone) return (10.0f);
if (widthTable <= 400.0f) return (10.0f);
if (widthTable <= 546.0f) return (31.0f);
if (widthTable >= 720.0f) return (45.0f);
return (31.0f + ceilf((widthTable - 547.0f)/13.0f));
}
I would like to supplement Matthew's answer with a code to set-up fixed margin.
- Subclass UITableViewCell.
- Implement setFrame:
- (void)setFrame:(CGRect)frame
{
CGFloat inset = 15.0;
CGFloat tableWidth = 400.0;
frame.origin.x -= [self groupedCellMarginWithTableWidth:tableWidth] - inset;
frame.size.width = frame.size.width + 2 * ([self groupedCellMarginWithTableWidth:tableWidth] - inset);
[super setFrame:frame];
}
This will set left and right margin for 15.0 while table width may vary.
Just in case anyone needs this, the function for the section title left margin when obtained from tableView:titleForHeaderInSection:
seems to be:
- (float)marginForSectionTitleOnGroupedTableView {
float width = self.width;
if (width <= 400) return 19;
else if (width >= 401 && width < 547) return 40;
else if (width >= 547 && width < 560) return 41;
else if (width >= 560 && width < 573) return 42;
else if (width >= 573 && width < 586) return 43;
else if (width >= 586 && width < 599) return 44;
else if (width >= 599 && width < 612) return 45;
else if (width >= 612 && width < 625) return 46;
else if (width >= 625 && width < 639) return 47;
else if (width >= 639 && width < 652) return 48;
else if (width >= 652 && width < 665) return 49;
else if (width >= 665 && width < 678) return 50;
else if (width >= 678 && width < 691) return 51;
else if (width >= 691 && width < 704) return 52;
else if (width >= 704 && width < 717) return 53;
// if (width >= 717)
return 54;
}
For widths greater than 401, the margin seems to be around 7.5% of the table view width; but when trying to align some other view with the section title, the alignment didn't work as expected; so the verbose approach seems to work better.
I have tried a different approach. But not sure whether it always work. I had a grouped UITableView and needed to make customized Header View. But as you know, when implementing viewForHeader inSection method we can not determine the margins for our created view. So, what I have done is firstly add a CGRect property to ViewController .m file:
@property(nonatomic)CGRect groupedCellRectangle;
and in UITableViewDelegate:
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{
static BOOL groupFrameInitialized = NO;
if(!groupFrameInitialized){
groupFrameInitialized = YES;
self.groupedCellRectangle = cell.contentView.frame;
}
}
after then, in my viewForHeader inSection method:
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
UIView *v = [[UIView alloc] initWithFrame:CGRectMake(self.groupedCellRectangle.origin.x, 0, self.groupedCellRectangle.size.width, 28)];
[v setBackgroundColor:[UIColor clearColor]];
UILabel *label = [[UILabel alloc] initWithFrame:v.frame];
label.text = @"KAF";
[v addSubview:label];
return v;
}
the result is as I assumed. groupedCellRectangle had successfully stored CGRect value with margin.
The idea behind this approach was UITableView always call viewForHeader method after willDisplay call.
Hope that helps...
精彩评论