开发者

indentationLevelForRowAtIndexPath not indenting custom cell

I have overridden the tableView:indentationLevelForRowAtIndexPath method in my UITableViewController derived class as follows:

- (NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSDictionary* item = [self.projects objectAtIndex:indexPath.row];
    int indentationLevel = [[item objectForKey:@"indent"] intValue];
    DLog (@"Indentation Level for Row %d : %d", indexPath.row, indentationLevel);
    return indentationLevel;
}

I initially thought that this was not being called but that was operator error (err, mine) and I hadn't defined the symbol DEBUG=1.

However, it is being called (duh me!) and this is the log output:

 -[RootViewController tableView:indentationLevelForRowAtIndexPath:] [Line 129] Indentation Level for Row 0 : 1
 -[RootViewController tableView:indentationLevelForRowAtIndexPath:] [Line 129] Indentation Level for Row 1 : 1
 -[RootViewController tableView:indentationLevelForRowAtIndexPath:] [Line 129] Indentation Level for Row 2 : 2
 -[RootViewController tableView:indentationLevelForRowAtIndexPath:] [Line 129] Indentation Level for Row 3 : 2
 -[RootViewController tableView:indentationLevelForRowAtIndexPath:] [Line 129] Indentation Level for Row 4 : 2
 -[RootViewController tableView:indentationLevelForRowAtIndexPath:] [Line 129] Indentation Level for Row 5 : 1
 -[RootViewController tableView:indentationLevelForRowAtIndexPath:] [Line 129] Indentation Level for Row 6 : 2
 -[RootViewController tableView:indentationLevelForRowAtIndexPath:] [Line 129] Indentation Level for Row 7 : 2
 -[RootViewController tableView:indentationLevelForRowAtIndexPath:] [Line 129] Indentation Level for Row 8 : 1

But, this is not affecting the layout of the cells. 开发者_运维技巧 No indentation.

This is my itemCellForRowAtIndexPath implementation, if that makes any difference:

-(UITableViewCell*)tableView:(UITableView *)tableView itemCellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString* cellIdentifier = @"projectItemCell";
    ProjectItemTableViewCell* cell = (ProjectItemTableViewCell*)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];

    if (cell == nil) {
        NSArray* nib = [[NSBundle mainBundle] loadNibNamed:@"ProjectItemTableViewCell" owner:self options:nil];
        for (id oneObject in nib) {
            if ([oneObject isKindOfClass:[ProjectItemTableViewCell class]]) {
                cell = (ProjectItemTableViewCell*)oneObject;
            }
        }
    }

    NSDictionary* item = [self.projects objectAtIndex:indexPath.row];
    cell.projectDescLabel.text = [item objectForKey:@"name"];
    cell.itemCountlabel.text = [NSString stringWithFormat:@"%d", [[item objectForKey:@"cache_count"] intValue]];
    cell.itemCountlabel.backgroundColor = [UIColor colorForHex:[item objectForKey:@"color"]];
    cell.indentationWidth = 20;
    return cell;
}

How do I indent a custom UITableViewCell which I have defined in Interface Builder?

If I change the itemCellForRowAtIndexPath to use a default UITableViewCell with the code below, then it indents fine.

static NSString* cellIdentifier = @"projectItemCell";
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier] autorelease];
}

NSDictionary* item = [self.projects objectAtIndex:indexPath.row];
cell.textLabel.text = [item objectForKey:@"name"];
cell.indentationWidth = 40;

return cell;


Yeah, it seems like custom table cells don't do this automatically? You need to override the layoutSubviews method in the table cell class. See this question for how to do this.

This code worked perfectly for me (although be careful if you are setting a custom height w/ the delegate as well, they seem to interfere with each other):

- (void)layoutSubviews
{
    [super layoutSubviews];
    float indentPoints = self.indentationLevel * self.indentationWidth;

    self.contentView.frame = CGRectMake(
        indentPoints,
        self.contentView.frame.origin.y,
        self.contentView.frame.size.width - indentPoints, 
        self.contentView.frame.size.height
    );
}

Edit for iOS8 and later

The above does work for me on iOS, but it causes subtle bugs when trying to autosize the height of the cell as well. There is n easier solution: If you have autolayout turned for the cell just set the left margin of the contentView:

override func layoutSubviews() {
    super.layoutSubviews()
    self.contentView.layoutMargins.left = CGFloat(self.indentationLevel) * self.indentationWidth
    self.contentView.layoutIfNeeded()
}


If you use a custom cell with constraints, the most convenient way is to set up a constraint that would shift all content from the left edge, and then update it according to the indentation level in your cell subclass.

Assuming indentationWidth is already set for the cell:

override var indentationLevel: Int {
    didSet {
        self.leftConstraint.constant = CGFloat(self.indentationLevel) * self.indentationWidth
    }
}


The indentation level is a property of the UITableViewCell itself. Try setting it on the cell when you create it, and return this value in tableView:indentationLevelForRowAtIndexPath:


Have you added the subviews of your ProjectItemTableViewCell to the cell's contentView? Also, you need to set the subviews' autoresizing masks so that they are repositioned when the contentView size changes.


Similar to the accepted answer, this is how it can be done in iOS 8 while still using layoutSubviews with AutoLayout instead.

With _viewConstraints as an NSMutableArray ivar and _imageView as the closest view to the left side of the cell's content view.

- (void)layoutSubviews
{
    float indentPoints = indentationLevel * [self indentationWidth];

    [self removeConstraints:_viewConstraints];
    [_viewConstraints removeAllObjects];

    NSDictionary *views = NSDictionaryOfVariableBindings(imageView);
    [_viewConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"H:|-(%f@1000)-[_imageView]", indentPoints] options:0 metrics:nil views:views]];
    [self addConstraints:_viewConstraints];
}

If you have AutoLayout constraints defining everything else in the view then this should push the whole view over the desired indentation amount.

NOTE if using Nib: You should define the constraint (in this case between _imageView and its super view) as >= some number (in my case it was 20). Then the original constraint, and the one being added/removed in layoutSubviews don't conflict with each other.

You should also consider calling the following in awakeFromNib

[_imageView setTranslatesAutoresizingMaskIntoConstraints:NO]

This is so the old "springs and struts" don't get in the way of the constraints you are adding.


The accepted answer could lead to an infinite loop on iOS8 in some cases. So it's better just to override setFrame of your custom UITableViewCell and adjust frame there.

-(void)setFrame:(CGRect)frame {
    float inset = self.indentationLevel * self.indentationWidth;

    frame.origin.x += inset;
    frame.size.width -= inset;

    [ super setFrame:frame ];
}


Have you accidentally overridden shouldIndentWhileEditing: to NO in your custom table cell class?


Constrain to the leading edge of the content view of the custom table cell you have in interface builder. For a simple margin, this seems to suffice. If you need to change the indentation programmatically, see Dean's answer. Or https://stackoverflow.com/a/7321461/5000071.


I used this code to indent my tableView cell. Initially it worked well, but later on this caused some problem (for example, interfering with my UITextView dynamic height update when indented, which is a subview of my tableView cell. Somehow my UITextView think it's width still is the original contentView's width).

float indentPoints = self.indentationLevel * self.indentationWidth;
self.contentView.frame = CGRectMake(
    indentPoints,
    self.contentView.frame.origin.y,
    self.contentView.frame.size.width - indentPoints, 
    self.contentView.frame.size.height
)

So I don't recommend the code above, instead I use the auto layout method as Dean's answer with a little difference (Swift version):

override func awakeFromNib() {
    super.awakeFromNib()
    self.indentationWidth = 20.0
    self.indentationLevel = 0
}
override func layoutSubviews() {
    super.layoutSubviews()
    let margin: CGFloat = 20.0
    let indentPoints = CGFloat(self.indentationLevel) * self.indentationWidth
    indentConstraint.constant = margin + indentPoints
}

The "indentConstraint" is a IBOutlet (leading constraint with the contentView), and the code is written in a custom tableViewCell subclass, it worked perfectly, and you don't need to remove or add any constraints, which is more expensive. I think the auto layout method is the better way to indent tableView cell.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜