From 820a6a8b4560f703e07104604589500b0feaf24e Mon Sep 17 00:00:00 2001 From: Star <576681253@qq.com> Date: Thu, 22 Sep 2016 12:14:30 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8DHeaderFooterView=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1、修复HeaderFooterView的BUG,你之前的HeaderFooterView没有经过configuration测试就发布了。 2、新增-fd_heightForCellWithStaticCell:configuration:,这是我的人人需求,也相信有不少人和我有一样 的需求。 --- .DS_Store | Bin 0 -> 6148 bytes Classes/UITableView+FDTemplateLayoutCell.h | 47 ++++-- Classes/UITableView+FDTemplateLayoutCell.m | 152 ++++++++++++++---- .../FDTemplateCell.xcscmblueprint | 2 +- 4 files changed, 161 insertions(+), 40 deletions(-) create mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..6679b7108c16896cbfa9786fb5bbee923cc5f673 GIT binary patch literal 6148 zcmeHK!AiqG5Pe&FXz?s#VV=eOXz=5>WPlz2spXFTDBC%oc(T|dm0W!rR`)b0DR`!sD)RNGAnd}P^Y z+U=~`GvExI3InX!B9n7Px6Xhw;0){-kncmJ3g(8rV)}H@ zq!xfEzmZ8emR>?)qG4{>EAkE{Xed!bgS8kz!|9KZ95QgG)2Y<|>!17o!yunI1J1xnF%ZVZvY0a^tF43Nq}E32Jyk^3^@_U? i4pJ%RS}DaB)Fkvr84z>BUXdP({|F=++&BY&%D@-5(MK@= literal 0 HcmV?d00001 diff --git a/Classes/UITableView+FDTemplateLayoutCell.h b/Classes/UITableView+FDTemplateLayoutCell.h index ed628fc..2284997 100644 --- a/Classes/UITableView+FDTemplateLayoutCell.h +++ b/Classes/UITableView+FDTemplateLayoutCell.h @@ -25,6 +25,9 @@ #import "UITableView+FDIndexPathHeightCache.h" #import "UITableView+FDTemplateLayoutCellDebug.h" + +#pragma mark - Cell + @interface UITableView (FDTemplateLayoutCell) /// Access to internal template layout cell for given reuse identifier. @@ -70,18 +73,17 @@ /// - (CGFloat)fd_heightForCellWithIdentifier:(NSString *)identifier cacheByKey:(id)key configuration:(void (^)(id cell))configuration; -@end - -@interface UITableView (FDTemplateLayoutHeaderFooterView) - -/// Returns header or footer view's height that registered in table view with reuse identifier. -/// -/// Use it after calling "-[UITableView registerNib/Class:forHeaderFooterViewReuseIdentifier]", -/// same with "-fd_heightForCellWithIdentifier:configuration:", it will call "-sizeThatFits:" for -/// subclass of UITableViewHeaderFooterView which is not using Auto Layout. -/// -- (CGFloat)fd_heightForHeaderFooterViewWithIdentifier:(NSString *)identifier configuration:(void (^)(id headerFooterView))configuration; +/** + + configure a undequere tableViewCell + + @param staticCell It's create by [[UITableView alloc] init]; + @param configuration It's could be NULL + + @return Static cell height + */ +- (CGFloat)fd_heightForCellWithStaticCell:(UITableViewCell *)staticCell configuration:(void (^)(id cell))configuration; @end @interface UITableViewCell (FDTemplateLayoutCell) @@ -106,3 +108,26 @@ @property (nonatomic, assign) BOOL fd_enforceFrameLayout; @end + + +#pragma mark - HeaderFooterView + +@interface UITableView (FDTemplateLayoutHeaderFooterView) + +/// Returns header or footer view's height that registered in table view with reuse identifier. +/// +/// Use it after calling "-[UITableView registerNib/Class:forHeaderFooterViewReuseIdentifier]", +/// same with "-fd_heightForCellWithIdentifier:configuration:", it will call "-sizeThatFits:" for +/// subclass of UITableViewHeaderFooterView which is not using Auto Layout. +/// +- (CGFloat)fd_heightForHeaderFooterViewWithIdentifier:(NSString *)identifier configuration:(void (^)(id headerFooterView))configuration; + +@end + +@interface UITableViewHeaderFooterView (FDTemplateLayoutHeaderFooterView) + +@property (nonatomic, assign) BOOL fd_isTemplateLayoutHeaderFooterView; + +@property (nonatomic, assign) BOOL fd_enforceFrameLayout; + +@end diff --git a/Classes/UITableView+FDTemplateLayoutCell.m b/Classes/UITableView+FDTemplateLayoutCell.m index 64305c1..eca2b7c 100644 --- a/Classes/UITableView+FDTemplateLayoutCell.m +++ b/Classes/UITableView+FDTemplateLayoutCell.m @@ -23,6 +23,9 @@ #import "UITableView+FDTemplateLayoutCell.h" #import + +#pragma mark - Cell + @implementation UITableView (FDTemplateLayoutCell) - (CGFloat)fd_systemFittingHeightForConfiguratedCell:(UITableViewCell *)cell { @@ -57,6 +60,7 @@ - (CGFloat)fd_systemFittingHeightForConfiguratedCell:(UITableViewCell *)cell { // 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]; + widthFenceConstraint.priority = UILayoutPriorityDefaultHigh; [cell.contentView addConstraint:widthFenceConstraint]; // Auto layout engine does its math @@ -175,11 +179,127 @@ - (CGFloat)fd_heightForCellWithIdentifier:(NSString *)identifier cacheByKey:(id< return height; } + +// Static Cell - by Star. +- (CGFloat)fd_heightForCellWithStaticCell:(UITableViewCell *)staticCell configuration:(void (^)(id cell))configuration { + + if (!staticCell) { + return 0; + } + + UITableViewCell *templateLayoutCell = staticCell; + + // 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]; +} + +@end + +@implementation UITableViewCell (FDTemplateLayoutCell) + +- (BOOL)fd_isTemplateLayoutCell { + return [objc_getAssociatedObject(self, _cmd) boolValue]; +} + +- (void)setFd_isTemplateLayoutCell:(BOOL)isTemplateLayoutCell { + objc_setAssociatedObject(self, @selector(fd_isTemplateLayoutCell), @(isTemplateLayoutCell), OBJC_ASSOCIATION_RETAIN); +} + +- (BOOL)fd_enforceFrameLayout { + return [objc_getAssociatedObject(self, _cmd) boolValue]; +} + +- (void)setFd_enforceFrameLayout:(BOOL)enforceFrameLayout { + objc_setAssociatedObject(self, @selector(fd_enforceFrameLayout), @(enforceFrameLayout), OBJC_ASSOCIATION_RETAIN); +} + +@end + + + + +#pragma mark - HeaderFooterView + +@implementation UITableViewHeaderFooterView (FDTemplateLayoutHeaderFooterView) + +- (BOOL)fd_isTemplateLayoutHeaderFooterView { + return [objc_getAssociatedObject(self, _cmd) boolValue]; +} + +- (void)setFd_isTemplateLayoutHeaderFooterView:(BOOL)fd_isTemplateLayoutHeaderFooterView { + objc_setAssociatedObject( + self, + @selector(fd_isTemplateLayoutCell), + @(fd_isTemplateLayoutHeaderFooterView), + OBJC_ASSOCIATION_RETAIN + ); +} + +- (BOOL)fd_enforceFrameLayout { + return [objc_getAssociatedObject(self, _cmd) boolValue]; +} + +- (void)setFd_enforceFrameLayout:(BOOL)enforceFrameLayout { + objc_setAssociatedObject(self, @selector(fd_enforceFrameLayout), @(enforceFrameLayout), OBJC_ASSOCIATION_RETAIN); +} + @end @implementation UITableView (FDTemplateLayoutHeaderFooterView) +- (CGFloat)fd_systemFittingHeightForConfiguratedHeaderFooterView:(UITableViewHeaderFooterView *)headerFooterView { + CGFloat contentViewWidth = CGRectGetWidth(self.frame); + + + CGFloat fittingHeight = 0; + + if (!headerFooterView.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:headerFooterView.contentView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:contentViewWidth]; + widthFenceConstraint.priority = UILayoutPriorityDefaultHigh; + [headerFooterView.contentView addConstraint:widthFenceConstraint]; + + // Auto layout engine does its math + fittingHeight = [headerFooterView.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height; + [headerFooterView.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. + if (headerFooterView.contentView.constraints.count > 0) { + if (!objc_getAssociatedObject(self, _cmd)) { + NSLog(@"[FDTemplateLayoutCell] Warning once only: Cannot get a proper cell height (now 0) from '- systemFittingSize:'(AutoLayout). You should check how constraints are built in cell, making it into 'self-sizing' cell."); + objc_setAssociatedObject(self, _cmd, @YES, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + } + } +#endif + // Try '- sizeThatFits:' for frame layout. + // Note: fitting height should not include separator view. + fittingHeight = [headerFooterView sizeThatFits:CGSizeMake(contentViewWidth, 0)].height; + + [self fd_debugLog:[NSString stringWithFormat:@"calculate using sizeThatFits - %@", @(fittingHeight)]]; + } + + if (fittingHeight == 0) { + fittingHeight = 44; + } + + return fittingHeight; +} + - (__kindof UITableViewHeaderFooterView *)fd_templateHeaderFooterViewForReuseIdentifier:(NSString *)identifier { + NSAssert(identifier.length > 0, @"Expect a valid identifier - %@", identifier); NSMutableDictionary *templateHeaderFooterViews = objc_getAssociatedObject(self, _cmd); @@ -194,6 +314,7 @@ - (__kindof UITableViewHeaderFooterView *)fd_templateHeaderFooterViewForReuseIde templateHeaderFooterView = [self dequeueReusableHeaderFooterViewWithIdentifier:identifier]; NSAssert(templateHeaderFooterView != nil, @"HeaderFooterView must be registered to table view for identifier - %@", identifier); templateHeaderFooterView.contentView.translatesAutoresizingMaskIntoConstraints = NO; + templateHeaderFooterView.fd_isTemplateLayoutHeaderFooterView = true; templateHeaderFooterViews[identifier] = templateHeaderFooterView; [self fd_debugLog:[NSString stringWithFormat:@"layout header footer view created - %@", identifier]]; } @@ -203,37 +324,12 @@ - (__kindof UITableViewHeaderFooterView *)fd_templateHeaderFooterViewForReuseIde - (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; + if (configuration) { + configuration(templateHeaderFooterView); } - - return fittingHeight; + return [self fd_systemFittingHeightForConfiguratedHeaderFooterView:templateHeaderFooterView]; } @end -@implementation UITableViewCell (FDTemplateLayoutCell) -- (BOOL)fd_isTemplateLayoutCell { - return [objc_getAssociatedObject(self, _cmd) boolValue]; -} - -- (void)setFd_isTemplateLayoutCell:(BOOL)isTemplateLayoutCell { - objc_setAssociatedObject(self, @selector(fd_isTemplateLayoutCell), @(isTemplateLayoutCell), OBJC_ASSOCIATION_RETAIN); -} - -- (BOOL)fd_enforceFrameLayout { - return [objc_getAssociatedObject(self, _cmd) boolValue]; -} - -- (void)setFd_enforceFrameLayout:(BOOL)enforceFrameLayout { - objc_setAssociatedObject(self, @selector(fd_enforceFrameLayout), @(enforceFrameLayout), OBJC_ASSOCIATION_RETAIN); -} - -@end diff --git a/FDTemplateCell.xcworkspace/xcshareddata/FDTemplateCell.xcscmblueprint b/FDTemplateCell.xcworkspace/xcshareddata/FDTemplateCell.xcscmblueprint index e6d8e9a..ae7a858 100644 --- a/FDTemplateCell.xcworkspace/xcshareddata/FDTemplateCell.xcscmblueprint +++ b/FDTemplateCell.xcworkspace/xcshareddata/FDTemplateCell.xcscmblueprint @@ -10,7 +10,7 @@ "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "6569ED7F-B9F6-4B04-BF61-CB6FDE03BD78", "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { "32d7d9b4-ffb1-4469-8922-27dbf3d99605++9332" : "svn\/iknow", - "45232C3CDBDF9DB333979E103A0429BCEB54D2EF" : "UITableView-FDTemplateLayoutCell" + "45232C3CDBDF9DB333979E103A0429BCEB54D2EF" : "UITableView-FDTemplateLayoutCell\/" }, "DVTSourceControlWorkspaceBlueprintNameKey" : "FDTemplateCell", "DVTSourceControlWorkspaceBlueprintVersion" : 204,