iOS中经常有需要给Label一个最合适的宽度和高度,京东和淘宝的搜索历史就是个典型应用:

关于计算方法,以前一直使用的是NSString的一个方法:

- (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options attributes:(nullable NSDictionary<NSAttributedStringKey, id> *)attributes context:(nullable NSStringDrawingContext *)context API_AVAILABLE(macos(10.11), ios(7.0));

使用的例子如下,这里是想获取合适的宽度,就要给宽度传入一个很大的值,然后高度给一个固定的值:

- (CGFloat)textWidth:(NSString *)text {
     CGFloat width = [text boundingRectWithSize:CGSizeMake(1000, 30) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : [UIFont systemFontOfSize:14]} context:nil].size.width + 20;

    return width;
}

但是这个方法其实很不准确,所以大多还会在返回的基础上,加一个值,例如上面这个代码就加20,以避免给的宽度过小,导致无法显示完全。
可即使这样做了,返回的这个宽度,我发现仍然有可能偏小,并会引起一些UI问题,例如我在做这个历史搜索界面的时候,就发现有些label,最右面会有一条线,如下所示:

我一开始以为是我不小心加了一条线在Label上,结果用xcode查看了视图层级,发现没有其他图层了,我怀疑可能给的这个宽度不对,导致出现的这个问题,我采用了另外的方法,这个是UIView的一个方法,不过宽度不对,导致这条线出现的更深层次的原因,应该是UILabel的实现的问题。

- (CGSize)sizeThatFits:(CGSize)size;     // return 'best' size to fit given size. does not actually resize view. Default is return existing view size

官方的注释已经告诉我们这个,这个可以给出最佳的size,使用的时候必须是已经实例化出来的View,比如Label的话,要先初始化,然后赋值text和font,例子如下:

    UILabel *contentLabel = [[UILabel alloc] initWithFrame:CGRectZero];
    contentLabel.font = [UIFont systemFontOfSize:14];
    contentLabel.text = historyArray[i];
    CGFloat nowWidth = [self widthForLabel:contentLabel andheight:kSearchHistorySubViewHeight]
    ......
- (CGFloat)widthForLabel:(UILabel *)label andheight:(CGFloat)height {
    CGSize sizeToFit = [label sizeThatFits:CGSizeMake(MAXFLOAT, height)];
    CGFloat width = sizeToFit.width + 10;

    return width;
}

这个计算出的宽度确实精确,但都贴着字符的边了,所以我们要加点宽度,不然很不美观。以后label再需要计算精确的宽度或高度,最好用这个方法了。

03-05 23:51