From 0661b9d1c9438ce9feaaad054f7575f8dfcc0c9e Mon Sep 17 00:00:00 2001 From: stone0117 Date: Sun, 25 Sep 2016 19:25:38 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fd=5FheightForHeaderFooterViewWithIdentifie?= =?UTF-8?q?r:configuration=20=E5=B0=91=E4=BA=86=E6=95=B0=E6=8D=AE=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Classes/UITableView+FDTemplateLayoutCell.m | 113 +++++++++++---------- 1 file changed, 60 insertions(+), 53 deletions(-) diff --git a/Classes/UITableView+FDTemplateLayoutCell.m b/Classes/UITableView+FDTemplateLayoutCell.m index 64305c1..4dbd527 100644 --- a/Classes/UITableView+FDTemplateLayoutCell.m +++ b/Classes/UITableView+FDTemplateLayoutCell.m @@ -27,22 +27,21 @@ @implementation UITableView (FDTemplateLayoutCell) - (CGFloat)fd_systemFittingHeightForConfiguratedCell:(UITableViewCell *)cell { CGFloat contentViewWidth = CGRectGetWidth(self.frame); - + // If a cell has accessory view or system accessory type, its content view's width is smaller // than cell's by some fixed values. if (cell.accessoryView) { contentViewWidth -= 16 + CGRectGetWidth(cell.accessoryView.frame); } else { static const CGFloat systemAccessoryWidths[] = { - [UITableViewCellAccessoryNone] = 0, - [UITableViewCellAccessoryDisclosureIndicator] = 34, - [UITableViewCellAccessoryDetailDisclosureButton] = 68, - [UITableViewCellAccessoryCheckmark] = 40, - [UITableViewCellAccessoryDetailButton] = 48 - }; + [UITableViewCellAccessoryNone] = 0, + [UITableViewCellAccessoryDisclosureIndicator] = 34, + [UITableViewCellAccessoryDetailDisclosureButton] = 68, + [UITableViewCellAccessoryCheckmark] = 40, + [UITableViewCellAccessoryDetailButton] = 48}; contentViewWidth -= systemAccessoryWidths[cell.accessoryType]; } - + // If not using auto layout, you have to override "-sizeThatFits:" to provide a fitting size by yourself. // This is the same height calculation passes used in iOS8 self-sizing cell's implementation. // @@ -50,22 +49,22 @@ - (CGFloat)fd_systemFittingHeightForConfiguratedCell:(UITableViewCell *)cell { // 2. Warning once if step 1 still returns 0 when using AutoLayout // 3. Try "- sizeThatFits:" if step 1 returns 0 // 4. Use a valid height or default row height (44) if not exist one - + CGFloat fittingHeight = 0; - + if (!cell.fd_enforceFrameLayout && contentViewWidth > 0) { // Add a hard width constraint to make dynamic content views (like labels) expand vertically instead // of growing horizontally, in a flow-layout manner. - NSLayoutConstraint *widthFenceConstraint = [NSLayoutConstraint constraintWithItem:cell.contentView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:contentViewWidth]; + NSLayoutConstraint * widthFenceConstraint = [NSLayoutConstraint constraintWithItem:cell.contentView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:contentViewWidth]; [cell.contentView addConstraint:widthFenceConstraint]; - + // Auto layout engine does its math fittingHeight = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height; [cell.contentView removeConstraint:widthFenceConstraint]; - + [self fd_debugLog:[NSString stringWithFormat:@"calculate using system fitting size (AutoLayout) - %@", @(fittingHeight)]]; } - + if (fittingHeight == 0) { #if DEBUG // Warn if using AutoLayout but get zero height. @@ -79,35 +78,35 @@ - (CGFloat)fd_systemFittingHeightForConfiguratedCell:(UITableViewCell *)cell { // Try '- sizeThatFits:' for frame layout. // Note: fitting height should not include separator view. fittingHeight = [cell sizeThatFits:CGSizeMake(contentViewWidth, 0)].height; - + [self fd_debugLog:[NSString stringWithFormat:@"calculate using sizeThatFits - %@", @(fittingHeight)]]; } - + // Still zero height after all above. if (fittingHeight == 0) { // Use default row height. fittingHeight = 44; } - + // Add 1px extra space for separator line if needed, simulating default UITableViewCell. if (self.separatorStyle != UITableViewCellSeparatorStyleNone) { fittingHeight += 1.0 / [UIScreen mainScreen].scale; } - + return fittingHeight; } - (__kindof UITableViewCell *)fd_templateCellForReuseIdentifier:(NSString *)identifier { NSAssert(identifier.length > 0, @"Expect a valid identifier - %@", identifier); - - NSMutableDictionary *templateCellsByIdentifiers = objc_getAssociatedObject(self, _cmd); + + NSMutableDictionary * templateCellsByIdentifiers = objc_getAssociatedObject(self, _cmd); if (!templateCellsByIdentifiers) { templateCellsByIdentifiers = @{}.mutableCopy; objc_setAssociatedObject(self, _cmd, templateCellsByIdentifiers, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - - UITableViewCell *templateCell = templateCellsByIdentifiers[identifier]; - + + UITableViewCell * templateCell = templateCellsByIdentifiers[identifier]; + if (!templateCell) { templateCell = [self dequeueReusableCellWithIdentifier:identifier]; NSAssert(templateCell != nil, @"Cell must be registered to table view for identifier - %@", identifier); @@ -116,7 +115,7 @@ - (__kindof UITableViewCell *)fd_templateCellForReuseIdentifier:(NSString *)iden templateCellsByIdentifiers[identifier] = templateCell; [self fd_debugLog:[NSString stringWithFormat:@"layout cell created - %@", identifier]]; } - + return templateCell; } @@ -124,17 +123,17 @@ - (CGFloat)fd_heightForCellWithIdentifier:(NSString *)identifier configuration:( if (!identifier) { return 0; } - - UITableViewCell *templateLayoutCell = [self fd_templateCellForReuseIdentifier:identifier]; - + + UITableViewCell * templateLayoutCell = [self fd_templateCellForReuseIdentifier:identifier]; + // Manually calls to ensure consistent behavior with actual cells. (that are displayed on screen) [templateLayoutCell prepareForReuse]; - + // Customize and provide content for our template cell. if (configuration) { configuration(templateLayoutCell); } - + return [self fd_systemFittingHeightForConfiguratedCell:templateLayoutCell]; } @@ -142,17 +141,17 @@ - (CGFloat)fd_heightForCellWithIdentifier:(NSString *)identifier cacheByIndexPat if (!identifier || !indexPath) { return 0; } - + // Hit cache if ([self.fd_indexPathHeightCache existsHeightAtIndexPath:indexPath]) { [self fd_debugLog:[NSString stringWithFormat:@"hit cache by index path[%@:%@] - %@", @(indexPath.section), @(indexPath.row), @([self.fd_indexPathHeightCache heightForIndexPath:indexPath])]]; return [self.fd_indexPathHeightCache heightForIndexPath:indexPath]; } - + CGFloat height = [self fd_heightForCellWithIdentifier:identifier configuration:configuration]; [self.fd_indexPathHeightCache cacheHeight:height byIndexPath:indexPath]; - [self fd_debugLog:[NSString stringWithFormat: @"cached by index path[%@:%@] - %@", @(indexPath.section), @(indexPath.row), @(height)]]; - + [self fd_debugLog:[NSString stringWithFormat:@"cached by index path[%@:%@] - %@", @(indexPath.section), @(indexPath.row), @(height)]]; + return height; } @@ -160,18 +159,18 @@ - (CGFloat)fd_heightForCellWithIdentifier:(NSString *)identifier cacheByKey:(id< if (!identifier || !key) { return 0; } - + // Hit cache if ([self.fd_keyedHeightCache existsHeightForKey:key]) { CGFloat cachedHeight = [self.fd_keyedHeightCache heightForKey:key]; [self fd_debugLog:[NSString stringWithFormat:@"hit cache by key[%@] - %@", key, @(cachedHeight)]]; return cachedHeight; } - + CGFloat height = [self fd_heightForCellWithIdentifier:identifier configuration:configuration]; [self.fd_keyedHeightCache cacheHeight:height byKey:key]; [self fd_debugLog:[NSString stringWithFormat:@"cached by key[%@] - %@", key, @(height)]]; - + return height; } @@ -181,15 +180,15 @@ @implementation UITableView (FDTemplateLayoutHeaderFooterView) - (__kindof UITableViewHeaderFooterView *)fd_templateHeaderFooterViewForReuseIdentifier:(NSString *)identifier { NSAssert(identifier.length > 0, @"Expect a valid identifier - %@", identifier); - - NSMutableDictionary *templateHeaderFooterViews = objc_getAssociatedObject(self, _cmd); + + NSMutableDictionary * templateHeaderFooterViews = objc_getAssociatedObject(self, _cmd); if (!templateHeaderFooterViews) { templateHeaderFooterViews = @{}.mutableCopy; objc_setAssociatedObject(self, _cmd, templateHeaderFooterViews, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - - UITableViewHeaderFooterView *templateHeaderFooterView = templateHeaderFooterViews[identifier]; - + + UITableViewHeaderFooterView * templateHeaderFooterView = templateHeaderFooterViews[identifier]; + if (!templateHeaderFooterView) { templateHeaderFooterView = [self dequeueReusableHeaderFooterViewWithIdentifier:identifier]; NSAssert(templateHeaderFooterView != nil, @"HeaderFooterView must be registered to table view for identifier - %@", identifier); @@ -197,23 +196,31 @@ - (__kindof UITableViewHeaderFooterView *)fd_templateHeaderFooterViewForReuseIde templateHeaderFooterViews[identifier] = templateHeaderFooterView; [self fd_debugLog:[NSString stringWithFormat:@"layout header footer view created - %@", identifier]]; } - + return templateHeaderFooterView; } - (CGFloat)fd_heightForHeaderFooterViewWithIdentifier:(NSString *)identifier configuration:(void (^)(id))configuration { - UITableViewHeaderFooterView *templateHeaderFooterView = [self fd_templateHeaderFooterViewForReuseIdentifier:identifier]; - - NSLayoutConstraint *widthFenceConstraint = [NSLayoutConstraint constraintWithItem:templateHeaderFooterView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:CGRectGetWidth(self.frame)]; - [templateHeaderFooterView addConstraint:widthFenceConstraint]; - CGFloat fittingHeight = [templateHeaderFooterView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height; - [templateHeaderFooterView removeConstraint:widthFenceConstraint]; - - if (fittingHeight == 0) { - fittingHeight = [templateHeaderFooterView sizeThatFits:CGSizeMake(CGRectGetWidth(self.frame), 0)].height; + + UITableViewHeaderFooterView * templateHeaderFooterView = [self fd_templateHeaderFooterViewForReuseIdentifier:identifier]; + [templateHeaderFooterView prepareForReuse]; + + /** 数据源 */ + configuration(templateHeaderFooterView); + + CGFloat contentViewWidth = CGRectGetWidth(self.frame); + + CGSize fittingSize = CGSizeZero; + + if (contentViewWidth > 0) { + NSLayoutConstraint * widthFenceConstraint = [NSLayoutConstraint constraintWithItem:templateHeaderFooterView.contentView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:contentViewWidth]; + [templateHeaderFooterView.contentView addConstraint:widthFenceConstraint]; + // Auto layout engine does its math + fittingSize = [templateHeaderFooterView.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]; + [templateHeaderFooterView.contentView removeConstraint:widthFenceConstraint]; } - - return fittingHeight; + + return fittingSize.height; } @end From 2279531e4503f998ba7a41ec7226451e8bbb302e Mon Sep 17 00:00:00 2001 From: stone0117 Date: Sun, 25 Sep 2016 19:37:19 +0800 Subject: [PATCH 2/2] 111 --- Classes/UITableView+FDTemplateLayoutCell.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/UITableView+FDTemplateLayoutCell.m b/Classes/UITableView+FDTemplateLayoutCell.m index 4dbd527..cb80354 100644 --- a/Classes/UITableView+FDTemplateLayoutCell.m +++ b/Classes/UITableView+FDTemplateLayoutCell.m @@ -206,7 +206,7 @@ - (CGFloat)fd_heightForHeaderFooterViewWithIdentifier:(NSString *)identifier con [templateHeaderFooterView prepareForReuse]; /** 数据源 */ - configuration(templateHeaderFooterView); + !configuration ?: configuration(templateHeaderFooterView); CGFloat contentViewWidth = CGRectGetWidth(self.frame);