iOS 10.3 Label高度计算问题 (UITableView+FDTemplateLayoutCell)

1.前言

今天有用户反馈说10.3的系统,有些文字显示不全,影响正式用户我哪里敢怠慢。急速的更新手机系统进行测试,发现真的是有问题,而且这个问题是UITableView+FDTemplateLayoutCell 引起的,计算的高度不准确引起的。

2.问题发现

经过测试发现问题出现在xib或者nib创建的cell 拉约束之后再用UITableView+FDTemplateLayoutCell 计算高度就会出现问题,用Masonry 配合UITableView+FDTemplateLayoutCell 使用没问题(至少我的是没有问题,当然如果你的有问题也可以看下我列举的解决办法,相信有适合你的)

3.解决问题

经过Gogle 发现目前为止很少有人提到这个问题(难道大家都没发现还是大家的都没问题,当然也有可能没用UITableView+FDTemplateLayoutCell 的),在UITableView+FDTemplateLayoutCell issues 和 Masonry issues 里面有很多提到这个问题的。究其原因好像iOS 10.3 会加一个宽一个高约束(Looks like iOS 10.3 has two additional constraints there for width/height),对Autolayout的约束有新的计算方式。

4.列举下解决问题的方法

1.设置 label的 preferredMaxLayoutWidth

这个方法亲测是可以的,但是有个问题nib 创建的cell 很多都不知道这个值到底是多少,就是知道也不能一个cell一个cell 的设置吧!至少我是不愿意 ,天啊几十种cell啊!当然有些人可能会图省事,随意设置一个吧,label.preferredMaxLayoutWidth = [UIScreen mainScreen].bounds.size.width - 80 这样你测试的是会发现确实换行了,但是真的行吗?label 的换行是要根据这个 preferredMaxLayoutWidth 类似计算文字高度的方法

- (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options attributes:(nullable NSDictionary<NSString *, id> *)attributes context:(nullable NSStringDrawingContext *)context NS_AVAILABLE(10_11, 7_0)

就像这个方法中size size的宽就是要设置label能够显示的宽,如果给的不对当然计算出的高度也会不对,如果给的小了计算的高度就高,给的大了计算的高度就低

  1. 加 [cell layoutIfNeeded]

因为有时候我发现第一次label显示的是没问题的,但是刷新一下就不行了,所以我想到在刷新重新算高度之前刷新下约束,这样就可以知道label的最大宽度限制了,当然我也不想在所以的cell 里面处理 所以在UITableView+FDTemplateLayoutCell 里面做了些处理

- (CGFloat)fd_heightForCellWithIdentifier:(NSString *)identifier configuration:(void (^)(id))configuration
  {
   if (!identifier) {
    return 0;
   }

// Fetch a cached template cell for `identifier`.
UITableViewCell *cell = [self fd_templateCellForReuseIdentifier:identifier];

// Manually calls to ensure consistent behavior with actual cells (that are displayed on screen).
[cell prepareForReuse];

// Customize and provide content for our template cell.
if (configuration) {
    configuration(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 CGFloat systemAccessoryWidths[] = {
        [UITableViewCellAccessoryNone] = 0,
        [UITableViewCellAccessoryDisclosureIndicator] = 34,
        [UITableViewCellAccessoryDetailDisclosureButton] = 68,
        [UITableViewCellAccessoryCheckmark] = 40,
        [UITableViewCellAccessoryDetailButton] = 48
    };
    contentViewWidth -= systemAccessoryWidths[cell.accessoryType];
}

CGSize fittingSize = CGSizeZero;
// If auto layout enabled, cell's contentView must have some constraints.
BOOL autoLayoutEnabled = cell.contentView.constraints.count > 0 && !cell.fd_enforceFrameLayout;

   if (autoLayoutEnabled) {
    // Add a hard width constraint to make dynamic content views (like labels) expand vertically instead
    // of growing horizontally, in a flow-layout manner.
    if (IOS_VERSION > 10.2) {
        [cell layoutIfNeeded];
    }
    NSLayoutConstraint *tempWidthConstraint =
    [NSLayoutConstraint constraintWithItem:cell.contentView
                                 attribute:NSLayoutAttributeWidth
                                 relatedBy:NSLayoutRelationEqual
                                    toItem:nil
                                 attribute:NSLayoutAttributeNotAnAttribute
                                multiplier:1.0
                                  constant:contentViewWidth];
    [cell.contentView addConstraint:tempWidthConstraint];
    // Auto layout engine does its math
    fittingSize = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
    [cell.contentView removeConstraint:tempWidthConstraint];
    
} else {
    
    // If not using auto layout, you have to override "-sizeThatFits:" to provide a fitting size by yourself.
    // This is the same method used in iOS8 self-sizing cell's implementation.
    // Note: fitting height should not include separator view.
    SEL selector = @selector(sizeThatFits:);
    BOOL inherited = ![cell isMemberOfClass:UITableViewCell.class];
    BOOL overrided = [cell.class instanceMethodForSelector:selector] != [UITableViewCell instanceMethodForSelector:selector];
    if (inherited && !overrided) {
        NSAssert(NO, @"Customized cell must override '-sizeThatFits:' method if not using auto layout.");
    }
    fittingSize = [cell sizeThatFits:CGSizeMake(contentViewWidth, 0)];
}

// Add 1px extra space for separator line if needed, simulating default UITableViewCell.
if (self.separatorStyle != UITableViewCellSeparatorStyleNone) {
    fittingSize.height += 1.0 / [UIScreen mainScreen].scale;
}

if (autoLayoutEnabled) {
    [self fd_debugLog:[NSString stringWithFormat:@"calculate using auto layout - %@", @(fittingSize.height)]];
} else {
    [self fd_debugLog:[NSString stringWithFormat:@"calculate using frame layout - %@", @(fittingSize.height)]];
}
  return fittingSize.height;
   }

*重点在这里


1.png

当然如果这个能满足你也是很好的,但是却满足不了我的工程,这个是可以完全解决nib 创建的cell 的高度问题,但是纯代码用Masonry加约束的却出现了问题,反而不能换行了,所以这个方法也不适合我,此路不通我再想他法继续往下看

3.给cell.contentView 加左右约束

在这里我这样理解的,既然xcode自动帮我们加的左右约束有问题,那我不用他的了, 我自己加

2.png

在同样的地方替换掉layoutIfNeeded,换成加左右约束, 记得后面加上priorityLow ,这样是避免跟cell 里面手动加的约束起冲突,这样就技能满足nib cell 也能满足纯代码cell ,也不用一个cell 一个cell 的改。至此这个问题完美的解决了(我的问题是解决了,你的解决了吗?欢迎留言共同探讨,小牛路过,不喜勿喷!)

<strong>什么,你还懒得敲,要我发源码!好吧忍不了你了<strong>
- (CGFloat)fd_heightForCellWithIdentifier:(NSString *)identifier configuration:(void (^)(id))configuration
{
if (!identifier) {
return 0;
}

// Fetch a cached template cell for `identifier`.
UITableViewCell *cell = [self fd_templateCellForReuseIdentifier:identifier];

// Manually calls to ensure consistent behavior with actual cells (that are displayed on screen).
[cell prepareForReuse];

// Customize and provide content for our template cell.
if (configuration) {
    configuration(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 CGFloat systemAccessoryWidths[] = {
        [UITableViewCellAccessoryNone] = 0,
        [UITableViewCellAccessoryDisclosureIndicator] = 34,
        [UITableViewCellAccessoryDetailDisclosureButton] = 68,
        [UITableViewCellAccessoryCheckmark] = 40,
        [UITableViewCellAccessoryDetailButton] = 48
    };
    contentViewWidth -= systemAccessoryWidths[cell.accessoryType];
}

CGSize fittingSize = CGSizeZero;
// If auto layout enabled, cell's contentView must have some constraints.
BOOL autoLayoutEnabled = cell.contentView.constraints.count > 0 && !cell.fd_enforceFrameLayout;

if (autoLayoutEnabled) {
    // Add a hard width constraint to make dynamic content views (like labels) expand vertically instead
    // of growing horizontally, in a flow-layout manner.
    if (IOS_VERSION > 10.2) {
        [cell.contentView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.left.mas_equalTo(0).priorityLow();
            make.right.mas_equalTo(0).priorityLow();
        }];
    }
    NSLayoutConstraint *tempWidthConstraint =
    [NSLayoutConstraint constraintWithItem:cell.contentView
                                 attribute:NSLayoutAttributeWidth
                                 relatedBy:NSLayoutRelationEqual
                                    toItem:nil
                                 attribute:NSLayoutAttributeNotAnAttribute
                                multiplier:1.0
                                  constant:contentViewWidth];
    [cell.contentView addConstraint:tempWidthConstraint];
    // Auto layout engine does its math
    fittingSize = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
    [cell.contentView removeConstraint:tempWidthConstraint];
    
} else {
    
    // If not using auto layout, you have to override "-sizeThatFits:" to provide a fitting size by yourself.
    // This is the same method used in iOS8 self-sizing cell's implementation.
    // Note: fitting height should not include separator view.
    SEL selector = @selector(sizeThatFits:);
    BOOL inherited = ![cell isMemberOfClass:UITableViewCell.class];
    BOOL overrided = [cell.class instanceMethodForSelector:selector] != [UITableViewCell instanceMethodForSelector:selector];
    if (inherited && !overrided) {
        NSAssert(NO, @"Customized cell must override '-sizeThatFits:' method if not using auto layout.");
    }
    fittingSize = [cell sizeThatFits:CGSizeMake(contentViewWidth, 0)];
}

// Add 1px extra space for separator line if needed, simulating default UITableViewCell.
if (self.separatorStyle != UITableViewCellSeparatorStyleNone) {
    fittingSize.height += 1.0 / [UIScreen mainScreen].scale;
}

if (autoLayoutEnabled) {
    [self fd_debugLog:[NSString stringWithFormat:@"calculate using auto layout - %@", @(fittingSize.height)]];
} else {
    [self fd_debugLog:[NSString stringWithFormat:@"calculate using frame layout - %@", @(fittingSize.height)]];
}

    return fittingSize.height;
 }

如果你的是其他版本的 自己对比找下,如果你是最新版的看下图

22.png

方法


33.png

位置


44.png

😝😝😝😝😝 客官慢走,喜欢点赞呗 😝😝😝😝😝

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容