登录 立即注册
金钱:

Code4App-iOS开发-iOS 开源代码库-iOS代码实例搜索-iOS特效示例-iOS代码例子下载-Code4App.com

有关UILabel的行高设置的探索

[复制链接]
来自: LBY5211ABC 分类: iOS精品源码 上传时间: 2016-11-21 18:38:09
Tag:UILabel 行高 attributedText Text

项目介绍:

有关UILabel的行高设置的探索

主题 《iOS开发》 by evan

导语

现在的UI,为了展现自己的独特的设计风格,总会“想方设法”的的“为难”开发。其中一项最基本的就是设计UILabel的行高。很多开发都会说,要设置行高,简单啊,设置attributedText就可以,如果深入去探索,会发现,并没有想象的那么简单。


需求

如果有这么一个UI需求

要做的第一步肯定的去设置行高,那么下面我们就来设置一下行高。

1. 创建NSMutableAttributedString设置行高

直接上代码

NSRange range = NSMakeRange(0, [text length]);
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:text];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
[paragraphStyle setLineSpacing:12.0];//调整行间距
[attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:range];
[attributedString addAttribute:NSFontAttributeName value:label.font range:range];
label.attributedText = attributedString;

这里按照UI效果图,设置LineSpacing为12,从16号字到20号字,中英文显示效果如下:

问题:虽然我们按照了效果图设置了行高为12,但是为啥实际效果,行高明显大于12呢?

2. 解决行高大于12的问题

出现这个问题,有可能有两个因素,要么是UI标注出错了,要么是代码设置出错了。经过验证,我发现UI标注并没有问题,代码也没问题。

问题出在UILabel上,回忆一下,在我们没有设置行高的年代,UIlabel会有一个默认的行高,经过测量,没设置行高的时候,默认行高大概在3px ~ 4px 之间,那么我就直接设置LineSpacing为8。

效果如下:

2. 现在有一个新的需求,最多显示两行

听到这个需求,觉得简单啊,那就来吧,设置numberOfLines为2不OK了。

事实如此吗?

问题:很奇怪,跟想象的完全不一样,是吧?文字显示的是2行,但是占用了整个UIlabel需要的高度

代码里是这样计算Label高度的:

NSDictionary *dic = @{NSFontAttributeName:label.font, NSParagraphStyleAttributeName:paragraphStyle};
NSStringDrawingOptions options = NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading;
CGFloat height =  [text boundingRectWithSize:CGSizeMake(_scrollView.bounds.size.width - 60, CGFLOAT_MAX) options:options attributes:dic context:nil].size.height;

首先在UILabel.h里可以看到:

// the underlying attributed string drawn by the label, if set, the label ignores the properties above.
@property(nullable, nonatomic,copy)   NSAttributedString *attributedText NS_AVAILABLE_IOS(6_0);  // default is nil

一旦设置了attributedText,以下这一堆属性将无效:

@property(nullable, nonatomic,copy)   NSString           *text;            // default is nil
@property(null_resettable, nonatomic,strong) UIFont      *font;            // default is nil (system font 17 plain)
@property(null_resettable, nonatomic,strong) UIColor     *textColor;       // default is nil (text draws black)
@property(nullable, nonatomic,strong) UIColor            *shadowColor;     // default is nil (no shadow)
@property(nonatomic)        CGSize             shadowOffset;    // default is CGSizeMake(0, -1) -- a top shadow
@property(nonatomic)        NSTextAlignment    textAlignment;   // default is NSTextAlignmentLeft
@property(nonatomic)        NSLineBreakMode    lineBreakMode;   // default is NSLineBreakByTruncatingTail. used for single and multiple lines of text

我们可以看到lineBreakMode也在里面,那我们就在NSMutableParagraphStyle里设置lineBreakMode :

[paragraphStyle setLineBreakMode:label.lineBreakMode];

运行后,Label的高度还是没什么改变,依旧是只显示2行,但是占用了所有高度。

问题应该是在boundingRectWithSize这个方法里,因为这里没有提供任何参数让我们设置UILabel的显示行数,所以,它计算的高度是整个Text需要显示的高度。

OK,既然如此我就换一个计算行高的方式:

CGSize size = [label sizeThatFits:CGSizeMake(_scrollView.bounds.size.width - 60, CGFLOAT_MAX)];
CGFloat height = size.height;

效果如下:

问题: 中文在显示一行的时候,文字底边距离UIlabel的下边,仍然有一个高度,这是怎么回事?

3. 探索单行中文底边距的问题

进入NSMutableParagraphStyle.h,看看有那么可以设置的属性:

@property(NS_NONATOMIC_IOSONLY) CGFloat lineSpacing;
@property(NS_NONATOMIC_IOSONLY) CGFloat paragraphSpacing;
@property(NS_NONATOMIC_IOSONLY) NSTextAlignment alignment;
@property(NS_NONATOMIC_IOSONLY) CGFloat firstLineHeadIndent;
@property(NS_NONATOMIC_IOSONLY) CGFloat headIndent;
@property(NS_NONATOMIC_IOSONLY) CGFloat tailIndent;
@property(NS_NONATOMIC_IOSONLY) NSLineBreakMode lineBreakMode;
@property(NS_NONATOMIC_IOSONLY) CGFloat minimumLineHeight;
@property(NS_NONATOMIC_IOSONLY) CGFloat maximumLineHeight;
@property(NS_NONATOMIC_IOSONLY) NSWritingDirection baseWritingDirection;
@property(NS_NONATOMIC_IOSONLY) CGFloat lineHeightMultiple;
@property(NS_NONATOMIC_IOSONLY) CGFloat paragraphSpacingBefore;
@property(NS_NONATOMIC_IOSONLY) float hyphenationFactor;
@property(null_resettable, copy, NS_NONATOMIC_IOSONLY) NSArray<NSTextTab *> *tabStops NS_AVAILABLE(10_0, 7_0);
@property(NS_NONATOMIC_IOSONLY) CGFloat defaultTabInterval NS_AVAILABLE(10_0, 7_0);
@property(NS_NONATOMIC_IOSONLY) BOOL allowsDefaultTighteningForTruncation NS_AVAILABLE(10_11, 9_0);

可设置的属性并不是很多,不过可一看到一个minimumLineHeight maximumLineHeight 。至此有了一个思考。最小行高应该是font所需要的行高,最高行高应该是font所需行高 + lineSpacing。

于是做如下设置:

[paragraphStyle setMinimumLineHeight:label.font.lineHeight];
[paragraphStyle setMaximumLineHeight:label.font.lineHeight + 8.0];

运行效果如下:

问题:多行 跟 单行的效果不统一,多行的时候底边没有边距,单行的时候底边有边距。这也不是我们所需要的效果,怎么办?

......
......
......

在我研究了多天之后,依然对此无解

不过有两个方案可以解决这个问题:

1.判断UILabel的行数,从而来改变UIlabel下面控件与它的间距:

BOOL isMultiLine = size.height > (label.font.lineHeight + MAX(label.font.lineHeight, 8)) ? YES : NO; // 判断UIlabel的行数

if (isMultiLine) {
    ... // 设置UIImageView.top = 10;
}
else {
    ... // 设置UIImageView.top = 10 - 8;
}  

2.利用CoreText去自定义Label,里面你可以畅所欲为,控制你想控制的一切。


如果有iOS技术达人,有这方面的经验,希望可以跟您交流,共同进步!!!

相关源码推荐:

我来说两句
*滑动验证:
所有评论(9)
phoiu 2016-11-22 14:20:15
感谢分享,code4app有你更精彩
回复
littleRed 2016-11-22 14:21:33
学习...学习...
回复
AlonMessi 2016-11-22 14:22:28
相当不错,感谢无私分享精神!
回复
BlueManlove 2016-11-22 14:23:31
感谢分享,楼主V5~
回复
kengsir 2016-11-22 14:24:23
支持,感谢,祝code4app越来越好~
回复
hellokenken 2016-11-22 14:26:03
内容很好,棒棒哒
回复
王颖博 2016-11-23 10:10:04
感谢分享,Code4App有你更精彩
回复
血色冰峰 2017-2-27 14:47:57
感谢分享,Code4App有你更精彩
回复
18516726100 2017-8-19 14:41:30
怎么没看到源码感谢分享,Code4App有你更精彩
回复
872 1 0
联系我们
首页/微信公众账号投稿

帖子代码编辑/版权问题

QQ:435399051,742864542

如何获得代码达人称号?

代码贡献英雄榜
用户名 下载数
通过邮件订阅最新 Code4App 信息
上一条 /4 下一条
联系我们
关闭
合作电话:
13802416937
Email:
435399051@qq.com
商务市场合作/投稿
问题反馈及帮助
联系我们

广告投放| Github|申请友链|手机版|Code4App ( 粤ICP备15117877号-1 )

快速回复 返回顶部 返回列表