intrinsicContentSize causes infinite loop in special case

雨燕双飞 提交于 2019-12-23 18:35:05

问题


I made a container view i call SimpleStackView. The idea is simple, any subviews are stacked on top of eachother. The width of a SimpleStackView determines the width of its subviews, and the height of a SimpleStackView is determined by the height of its subviews.

I do it in layoutSubviews where i call sizeThatFits on each subview and layout them on top of eachother using the returned heights. The sum of those heights also determine what is returned from both the sizeThatFits override and intrinsicContentSize override of SimpleStackView.

I support iOS 7 so i cant use UIStackView.

I use AutoLayout to layout most things in my app. My SimpleStackView works fine in many places where its laid out using AutoLayout next to other views (i rely on its intrinsicContentSize to define its height, no height constraints), except in one case where a SimpleStackView is put in the contentView of a UITableViewCell in a UITableView. In that one case, an infinite loop is triggered. Im not an AutoLayout guru. I might be missing something about how intrinsicContetSizes are used inside AutoLayout? What could be the case of this? How do i use intrinsicContentSize properly so it works correctly in all cases?

The code of SimpleStackView is relatively short; here's the full class implementation:

@implementation SimpleStackView

@synthesize rowSpacing=_rowSpacing;

- (void)layoutSubviews
{
    [super layoutSubviews];

    [self sizeToFit];
    [self invalidateIntrinsicContentSize];

    CGFloat nextRowTop = 0;
    for (UIView *view in self.subviews)
    {
        CGSize size = [view sizeThatFits:CGSizeMake(self.bounds.size.width, view.bounds.size.height)];
        view.frame = CGRectMake(0, nextRowTop, self.bounds.size.width, size.height);
        nextRowTop += view.frame.size.height + self.rowSpacing;
    }
}

- (CGSize)sizeThatFits:(CGSize)size
{
    CGFloat sumOfHeights = 0;
    for (UIView *view in self.subviews) {
        sumOfHeights += [view sizeThatFits:CGSizeMake(size.width, view.bounds.size.height)].height;
    }
    CGFloat sumOfRowSpacings = MAX(0, (int)self.subviews.count - 1) * self.rowSpacing;
    return CGSizeMake(size.width, sumOfHeights + sumOfRowSpacings);
}

- (CGSize)intrinsicContentSize
{
    CGFloat intrinsicHeight = [self sizeThatFits:self.bounds.size].height;
    return CGSizeMake(UIViewNoIntrinsicMetric, intrinsicHeight);
}

// i tried this to fix the infinite loop; didnt work was still stuck in infinite loop
//- (void)setFrame:(CGRect)frame
//{
//    CGRect frameBefore = self.frame;
//    [super setFrame:frame];
//    if (NO == CGRectEqualToRect(frameBefore, frame))
//        [self invalidateIntrinsicContentSize];
//}

@end

edit: I forgot to mention; the UITableCellView that causes the infinite loop has an unbroken chain of constraints from the top of contentView to bottom of contentView. The infinite loop stops happening when i remove one of the constraints to break the chain. I'd like to keep the constraints, they are there to compress a multiline UILabel when row height is small (which is set in the UITableViewDelegate's heightForRowAtIndexPath).

来源:https://stackoverflow.com/questions/37541319/intrinsiccontentsize-causes-infinite-loop-in-special-case

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!