UITableViewCell高度裁剪内容

时间:2014-09-01 12:52:37

标签: ios objective-c uitableview autolayout heightforrowatindexpath

我有一个自定义的UITableViewCell,我正在尝试使用rewiews加载。流程是:我从单元格的contentView(setWithLoadingState方法)中的UIActivityIndi​​cator开始,在我从API返回响应后,我设置了带有注释/错误消息的单元格(setWithErrorMessage:/ setWithReviews :)。当我尝试使用评论设置单元格时出现问题(setWithReviews:method)。

此外,该单元格是IB中的静态单元格。

问题在于,有时布局确实是错误的,我无法弄清楚原因。控制台还警告我关于不可满足的约束,但据我所知,这可能是由于UITableView在beginUpdates和endUpdates之间制作的动画。

控制台消息(错误多次出现。):

    Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSAutoresizingMaskLayoutConstraint:0xbc32930 h=--& v=--& V:[UITableViewCellContentView:0xbcd3330(40.5)]>",
    "<NSLayoutConstraint:0xbed2820 V:|-(NSSpace(20))-[UIView:0xbecc350]   (Names: '|':UITableViewCellContentView:0xbcd3330 )>",
    "<NSLayoutConstraint:0xbcb8540 V:[UIView:0xbecc350]-(NSSpace(8))-[UIView:0xbec7870]>",
    "<NSLayoutConstraint:0xbcb8fe0 V:[UIView:0xbec7870(0.5)]>",
    "<NSLayoutConstraint:0xbc24e00 V:[UIView:0xbec7870]-(NSSpace(8))-[UIView:0xbe0a380]>",
    "<NSLayoutConstraint:0x1194bd10 V:[UIView:0xbe0a380]-(NSSpace(8))-[UIView:0xbc358e0]>",
    "<NSLayoutConstraint:0x119560c0 V:[UIView:0xbc358e0(0.5)]>",
    "<NSLayoutConstraint:0x1194bd60 V:[UIView:0xbc358e0]-(NSSpace(8))-[UIView:0xbcd71a0]>",
    "<NSLayoutConstraint:0x119480a0 V:[UIView:0xbcd71a0]-(NSSpace(8))-[UIView:0x1194b860]>",
    "<NSLayoutConstraint:0x11948fc0 V:[UIView:0x1194b860(0.5)]>",
    "<NSLayoutConstraint:0x11948ff0 V:[UIView:0x1194b860]-(NSSpace(8))-[UIView:0x1193f880]>",
    "<NSLayoutConstraint:0xbeca990 V:[UIView:0x1193f880]-(NSSpace(8))-[UIView:0x1194c360]>",
    "<NSLayoutConstraint:0xbeca9c0 V:[UIView:0x1194c360(0.5)]>",
    "<NSLayoutConstraint:0xbeca9f0 V:[UIView:0x1194c360]-(NSSpace(8))-[UIView:0x1194c1b0]>",
    "<NSLayoutConstraint:0xbed69c0 V:[UIView:0x1194c1b0]-(NSSpace(8))-[UIView:0xbec8b10]>",
    "<NSLayoutConstraint:0xbed69f0 V:[UIView:0xbec8b10(0.5)]>",
    "<NSLayoutConstraint:0xbed6a20 V:[UIView:0xbec8b10]-(NSSpace(8))-[UIView:0xbec8960]>",
    "<NSLayoutConstraint:0xbedbf50 V:[UIView:0xbec8960]-(NSSpace(8))-[UIView:0xbede4b0]>",
    "<NSLayoutConstraint:0xbeda750 V:[UIView:0xbede4b0(0.5)]>",
    "<NSLayoutConstraint:0xbeda5d0 V:[UIView:0xbede4b0]-(NSSpace(8))-[UIView:0xbede300]>",
    "<NSLayoutConstraint:0xbc1e380 V:[UIView:0xbede300]-(NSSpace(8))-[UIView:0xbed6200]>",
    "<NSLayoutConstraint:0xbc1e3b0 V:[UIView:0xbed6200(0.5)]>",
    "<NSLayoutConstraint:0xbc235e0 V:[UIView:0xbed6200]-(NSSpace(8))-[UIView:0xbed8e20]>",
    "<NSLayoutConstraint:0xbfbb850 V:[UIView:0xbed8e20]-(NSSpace(8))-[UIView:0xbcb56f0]>",
    "<NSLayoutConstraint:0xbfbb880 V:[UIView:0xbcb56f0(0.5)]>",
    "<NSLayoutConstraint:0xbfb6400 V:[UIView:0xbcb56f0]-(NSSpace(8))-[UIView:0xbc35cd0]>",
    "<NSLayoutConstraint:0xbfda4f0 V:[UIView:0xbc35cd0]-(NSSpace(20))-|   (Names: '|':UITableViewCellContentView:0xbcd3330 )>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0xbfb6400 V:[UIView:0xbcb56f0]-(NSSpace(8))-[UIView:0xbc35cd0]>

Break on objc_exception_throw to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.

源代码:

- (void)setWithLoadingState
{
    [self clear];

    UIActivityIndicatorView *av = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
    [av startAnimating];
    [av setTranslatesAutoresizingMaskIntoConstraints:NO];
    [self.contentView addSubview:av];

    NSDictionary *views = NSDictionaryOfVariableBindings(av);

    NSLayoutConstraint *centerX = [NSLayoutConstraint constraintWithItem:av attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeCenterX multiplier:1 constant:0];
    NSArray *cV =
    [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-10-[av]-10-|"
                                            options:0
                                            metrics:nil
                                              views:views];
    [self.contentView addConstraints:[cV arrayByAddingObjectsFromArray:@[centerX]]];

    [self updateConstraintsIfNeeded];
    [self layoutIfNeeded];
}

- (void)setWithReviews:(NSDictionary *)reviews
{
    [self clear];

    UIView *topView         = self.contentView;

    // Create subviews with ratings.
    for (NSDictionary *review in reviews[REVIEWS])
    {
        NSNumber *ratingViewWidth   = @90;
        NSNumber *ratingViewHeight  = @15;
        UIView *reviewContentView = [[UIView alloc] init];
        UIView *reviewHeaderView  = [[UIView alloc] init];
        UIView *reviewInfoView    = [[UIView alloc] init];
        UIView *separatorView     = [[UIView alloc] init];

        NSString *reviewerEmail         = review[REVIEWER_INFO][EMAIL];
        NSDate *reviewCreatedAtDate  = [NSDate dateWithString:review[CREATED_AT][DATE] format:kDateTimeFormatServer];
        NSString *dateTimeFormat     = [((NSString *)[I18n singleton].conventions[DATETIME]) PHPDateFormatToNSDateFormat];
        NSString *reviewCreatedAt    = [reviewCreatedAtDate stringValueWithFormat:dateTimeFormat];
        NSNumber *reviewOverallRating   = review[RATINGS][RATING];
        NSString *reviewComment         = review[COMMENT];

        UILabel *reviewerEmailLbl           = [[UILabel alloc] init];
        UILabel *reviewerCreatedAtLbl       = [[UILabel alloc] init];
        UIView *reviewerOverallRatingView   = [[UIView alloc] init];
        UILabel *reviewerCommentLbl         = [[UILabel alloc] init];

        reviewerEmailLbl.textAlignment      = NSTextAlignmentLeft;
        reviewerEmailLbl.textColor          = [UIColor grayColor];
        reviewerEmailLbl.text               = reviewerEmail;
        reviewerEmailLbl.font               = [UIFont systemFontOfSize:12];

        reviewerCreatedAtLbl.textAlignment  = NSTextAlignmentLeft;
        reviewerCreatedAtLbl.textColor      = [UIColor grayColor];
        reviewerCreatedAtLbl.text           = reviewCreatedAt;
        reviewerCreatedAtLbl.font           = [UIFont systemFontOfSize:12];

        reviewerCommentLbl.textAlignment    = NSTextAlignmentNatural;
        reviewerCommentLbl.textColor        = [UIColor blackColor];
        reviewerCommentLbl.text             = reviewComment;
        reviewerCommentLbl.font             = [UIFont systemFontOfSize:14];
        reviewerCommentLbl.numberOfLines    = 0;

        UIView *starRatingView = [self getRatingViewWithFrame:CGRectMake(0, 0, ratingViewWidth.integerValue, ratingViewHeight.integerValue) rating:reviewOverallRating];

        separatorView.backgroundColor = [UIColor lightGrayColor];

        [reviewContentView          setTranslatesAutoresizingMaskIntoConstraints:NO];
        [reviewHeaderView           setTranslatesAutoresizingMaskIntoConstraints:NO];
        [reviewInfoView             setTranslatesAutoresizingMaskIntoConstraints:NO];
        [reviewerEmailLbl           setTranslatesAutoresizingMaskIntoConstraints:NO];
        [reviewerCreatedAtLbl       setTranslatesAutoresizingMaskIntoConstraints:NO];
        [reviewerOverallRatingView  setTranslatesAutoresizingMaskIntoConstraints:NO];
        [reviewerCommentLbl         setTranslatesAutoresizingMaskIntoConstraints:NO];
        [starRatingView             setTranslatesAutoresizingMaskIntoConstraints:NO];
        [separatorView              setTranslatesAutoresizingMaskIntoConstraints:NO];


        NSDictionary *views = NSDictionaryOfVariableBindings(reviewContentView, topView, reviewerEmailLbl, reviewerCreatedAtLbl, reviewerCommentLbl, reviewerOverallRatingView, starRatingView, reviewHeaderView, reviewInfoView, separatorView);
        NSDictionary *metrics = NSDictionaryOfVariableBindings(ratingViewWidth, ratingViewHeight);

        [reviewerOverallRatingView addSubview:starRatingView];

        [reviewInfoView addSubview:reviewerEmailLbl];
        [reviewInfoView addSubview:reviewerCreatedAtLbl];
        [reviewHeaderView addSubview:reviewInfoView];
        [reviewHeaderView addSubview:reviewerOverallRatingView];
        [reviewContentView addSubview:reviewHeaderView];
        [reviewContentView addSubview:reviewerCommentLbl];
        [self.contentView addSubview:separatorView];
        [self.contentView addSubview:reviewContentView];

        NSArray *cH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[starRatingView]|" options:0 metrics:nil views:views];
        NSArray *cV = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[starRatingView]|" options:0 metrics:nil views:views];
        [reviewerOverallRatingView addConstraints:[cH arrayByAddingObjectsFromArray:cV]];

        cH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[reviewerEmailLbl]->=0-|" options:0 metrics:nil views:views];
        [reviewInfoView addConstraints:cH];
        cH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[reviewerCreatedAtLbl]->=0-|" options:0 metrics:nil views:views];
        [reviewInfoView addConstraints:cH];
        cV = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[reviewerEmailLbl]-5-[reviewerCreatedAtLbl]|" options:0 metrics:nil views:views];
        [reviewInfoView addConstraints:cV];

        cH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[reviewInfoView]-5-[reviewerOverallRatingView(ratingViewWidth)]|" options:0 metrics:metrics views:views];
        [reviewHeaderView addConstraints:cH];
        cV = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[reviewInfoView]->=0-|" options:0 metrics:nil views:views];
        [reviewHeaderView addConstraints:cV];
        cV = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[reviewerOverallRatingView(ratingViewHeight)]->=0-|" options:0 metrics:metrics views:views];
        [reviewHeaderView addConstraints:cV];



        cV = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[reviewHeaderView]-5-[reviewerCommentLbl]|" options:0 metrics:nil views:views];
        cH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[reviewHeaderView]|" options:0 metrics:nil views:views];
        [reviewContentView addConstraints:[cH arrayByAddingObjectsFromArray:cV]];
        cH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[reviewerCommentLbl]|" options:0 metrics:nil views:views];
        [reviewContentView addConstraints:cH];



        if (topView != self.contentView)
        {
            NSArray *separatorConstraintH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-40-[separatorView]-40-|" options:0 metrics:nil views:views];
            [self.contentView addConstraints:separatorConstraintH];
        } // Adding separator horisontal constraint.

        NSArray *constraintsContainerH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[reviewContentView]-|" options:0 metrics:nil views:views];
        [self.contentView addConstraints:constraintsContainerH];

        NSArray *constraintsContainerV;
        if (topView == self.contentView)
            constraintsContainerV = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[reviewContentView]" options:0 metrics:nil views:views];
        else
            constraintsContainerV = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[topView]-[separatorView(0.5@1000)]-[reviewContentView]" options:0 metrics:nil views:views];
        [self.contentView addConstraints:constraintsContainerV];

        topView = reviewContentView;
    }

    if (topView == self.contentView)
    {
        UILabel *errorLabel = [[UILabel alloc] init];
        errorLabel.textColor = [UIColor grayColor];
        errorLabel.textAlignment = NSTextAlignmentCenter;
        errorLabel.text = [I18n singleton].translations[I18N_NO_REVIEWS];
        errorLabel.numberOfLines = 0;
        [errorLabel setTranslatesAutoresizingMaskIntoConstraints:NO];

        [self.contentView addSubview:errorLabel];

        NSDictionary *views = NSDictionaryOfVariableBindings(errorLabel);
        NSArray *constraintsH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[errorLabel]-|" options:0 metrics:nil views:views];
        NSArray *constraintsV = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[errorLabel]-|" options:0 metrics:nil views:views];

        [self.contentView addConstraints:[constraintsH arrayByAddingObjectsFromArray:constraintsV]];
    }
    else
    {
        NSDictionary *views = NSDictionaryOfVariableBindings(topView);
        NSArray *constraintsV = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[topView]-|" options:0 metrics:nil views:views];
        [self.contentView addConstraints:constraintsV];
    }

    [self updateConstraintsIfNeeded];
    [self layoutIfNeeded];
}

- (TQStarRatingView *)getRatingViewWithFrame:(CGRect)frame rating:(NSNumber *)rating
{
    TQStarRatingView *starRatingView = [[TQStarRatingView alloc] initWithFrame:frame numberOfStar:5];
    [starRatingView setScore:rating.floatValue withAnimation:NO];
    starRatingView.userInteractionEnabled = NO;
    starRatingView.backgroundColor = [UIColor clearColor];

    return starRatingView;
}

- (void)setWithErrorMessage:(NSString *)message
{
    [self clear];

    UILabel *errorLabel = [[UILabel alloc] init];
    errorLabel.textColor = [UIColor grayColor];
    errorLabel.textAlignment = NSTextAlignmentCenter;
    errorLabel.text = [I18n singleton].translations[I18N_COULD_NOT_GET_REVIEWS];
    errorLabel.numberOfLines = 0;
    [errorLabel setTranslatesAutoresizingMaskIntoConstraints:NO];

    [self.contentView addSubview:errorLabel];

    NSDictionary *views = NSDictionaryOfVariableBindings(errorLabel);
    NSArray *constraintsH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[errorLabel]-|" options:0 metrics:nil views:views];
    NSArray *constraintsV = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[errorLabel]-|" options:0 metrics:nil views:views];

    [self.contentView addConstraints:[constraintsH arrayByAddingObjectsFromArray:constraintsV]];

    [self updateConstraintsIfNeeded];
    [self layoutIfNeeded];
}

#pragma mark - Clear;

- (void)clear
{
    [self.contentView removeAllSubviews];

    [self updateConstraintsIfNeeded];
    [self layoutIfNeeded];
}

HeightForRowAtIndexPath方法:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];

    [cell setNeedsUpdateConstraints];
    [cell updateConstraintsIfNeeded];

    cell.bounds = CGRectMake(0.0f, 0.0f, CGRectGetWidth(tableView.bounds), CGRectGetHeight(cell.bounds));

    [cell setNeedsLayout];
    [cell layoutIfNeeded];

    CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;

    height += 1.0f;

    return height;
}

结果:

http://i.imgur.com/bnBe4YC.png

查看层次结构:

http://i.imgur.com/Z8XQzo8.png

提前致谢并对于凌乱的代码感到抱歉(还没有重构它:))。

0 个答案:

没有答案