IOS UILabel中的文字吸顶(顶部对齐)

释放双眼,带上耳机,听听看~!

需求

使用过UILabel,会发现UILabel可以设置三种对齐方式,靠左,居中,靠右。满心欢喜地以为原来就这么回事,苹果都帮我们做好了呀。

可是,接到一个需求是使文字在cell的子控件UILabel中文字吸顶,找了半天都没有这样的属性..

设置

设置了UILabel的高度>=60,Lines=0,于是乎实现出来的效果是酱紫的:
实现-1

产品并不买账,说了吸顶就是要吸顶哦,看起来美观一点~
苹果爸爸也没有那么体贴啊这个都不帮我们做…
这个时候只能靠聪慧的大(Stack)脑(Overflow)了。


解决办法

经过苦苦搜寻,发现了几个解决办法哦,点击这里可以看原文

原文撸主的需求和我很像,要在两行的UILabel中实现吸顶。
需求

热心的网友给出了解决办法,其中有五个是比较好使的,大家可以根据需求自己采用哈!

1)用sizeToFit修改Label的高度

没法直接改变UILabel的垂直对齐方式(UILabel没有这个属性),但是把 label 的 frame 高度改小也能实现相同的效果。

为了看得清楚,把 label 背景标为橘黄色,如图:
1

如果内容长度超过一行,把numberOfLines设成 0(就是不限制行数)。

有一个问题是,不管你设置了文字是水平居中还是右对齐,那么执行完sizeToFit后 frame 宽度也缩小了,文字会缩到左上角,效果都比较差,如图:
3

解决方法是把 label 的宽度先用变量保存起来,执行完sizeToFit之后再设回来,就解决了上面的问题,如图:
2

另外要注意,sizeToFit 会把 label 的当前宽度当做最大宽度,执行之后宽度只会比变窄,不会变宽。
注意

Last but not least! 如果你是使用Auto Layout 的 NIB 和 Storyboard,Mark Amery 在评论中补充了解决方案:

如果 nib 或 storyboard 里用了 autoLayout,那么在viewDidLoad调sizeToFit是不管用的,因为实际顺序是先执行viewDidLoad再执行 autoLayout,执行 autoLayout 的时候会把 sizeToFit 的结果覆盖掉。
不过,在viewDidLayoutSubviews里调sizeToFit是管用的。

2)末尾补充换行符”n”

一个更简单粗暴的办法,是把UILabel的 “line break mode” 设为 “Clip”,然后直接在末尾加一些换行符。

myLabel.lineBreakMode = UILineBreakModeClip;
myLabel.text = [displayString stringByAppendingString:"nnnn"];

不过,这个方法不是万能的,当Label文字超出范围并且需要在末尾显示“…”就不行了,不会自动缩略末尾变成“…”。

3)用UITextField代替UILabel

用UITextField取代UILabel,默认就是顶端对齐的。
同时把userInterationEnabled设为NO,让它不能滚动。

4)重写UILabel的drawTextInRect:方法

创建一个UILabel的子类,用起来非常方便:

// TopLeftLabel.h
#import <Foundation/Foundation.h>
@interface TopLeftLabel : UILabel {
}
@end
// TopLeftLabel.m
#import "TopLeftLabel.h"
@implementation TopLeftLabel
- (id)initWithFrame:(CGRect)frame {
return [super initWithFrame:frame];
}
- (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines {
CGRect textRect = [super textRectForBounds:bounds limitedToNumberOfLines:numberOfLines];
textRect.origin.y = bounds.origin.y;
return textRect;
}
-(void)drawTextInRect:(CGRect)requestedRect {
CGRect actualRect = [self textRectForBounds:requestedRect limitedToNumberOfLines:self.numberOfLines];
[super drawTextInRect:actualRect];
}
@end

5)自定义UILabel的分类

直接上代码…:

#pragma mark VerticalAlign
@interface UILabel (VerticalAlign)
- (void)alignTop;
- (void)alignBottom;
@end
@implementation UILabel (VerticalAlign)
- (void)alignTop
{
CGSize fontSize = [self.text sizeWithFont:self.font];
double finalHeight = fontSize.height * self.numberOfLines;
double finalWidth = self.frame.size.width;    //expected width of label
CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];
int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;
for(int i=0; i<= newLinesToPad; i++)
{
self.text = [self.text stringByAppendingString:@" n"];
}
}
- (void)alignBottom
{
CGSize fontSize = [self.text sizeWithFont:self.font];
double finalHeight = fontSize.height * self.numberOfLines;
double finalWidth = self.frame.size.width;    //expected width of label
CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];
int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;
for(int i=0; i< newLinesToPad; i++)
{
self.text = [NSString stringWithFormat:@" n%@",self.text];
}
}
@end

调用只需用下面两行代码即可实现效果。

[myLabel alignTop];
[myLabel alignBottom];

实现

在本项目中,使用第一种方式,一句代码就解决了问题!因为撸主是使用xib来做cell,一开始写在了layoutSubviews方法中

- (void)layoutSubviews{
[super layoutSubviews];
[self.captionLabel sizeToFit];
[self.containerView clipsToCornerRadius:8];
}

但是,出现了第二次滑动到指定位置才有效,并且有奇奇怪怪的效果:
11
考虑到是cell的重用缓存,以及view的生命周期顺序问题:layoutSubviews方法调用先于drawRect
我要在View绘制子控件时再次确定cell的布局,于是把代码放到drawRect中:

- (void)drawRect:(CGRect)rect{
[self.captionLabel sizeToFit];
[self.containerView clipsToCornerRadius:8];
}

22

如果还是有问题,可以考虑直接用其他方式,如后来出现有UILabel文字显示不全的现象,最后用方法二代替了~

人已赞赏
iOS文章

iOS开发 - touchBegan事件判断点击的位置在View上还是在View的子View上

2020-3-30 4:31:56

iOS文章

iOS开发小知识之改变UIlabel的行间距和字间距

2020-3-30 5:47:28

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
有新消息 消息中心
搜索