使用过UILabel,会发现UILabel可以设置三种对齐方式,靠左,居中,靠右。满心欢喜地以为原来就这么回事,苹果都帮我们做好了呀。
可是,接到一个需求是使文字在cell的子控件UILabel中文字吸顶,找了半天都没有这样的属性..
设置了UILabel的高度>=60,Lines=0,于是乎实现出来的效果是酱紫的:
产品并不买账,说了吸顶就是要吸顶哦,看起来美观一点~
苹果爸爸也没有那么体贴啊这个都不帮我们做…
这个时候只能靠聪慧的大(Stack)脑(Overflow)了。
经过苦苦搜寻,发现了几个解决办法哦,点击这里可以看原文!
原文撸主的需求和我很像,要在两行的UILabel中实现吸顶。
热心的网友给出了解决办法,其中有五个是比较好使的,大家可以根据需求自己采用哈!
没法直接改变UILabel的垂直对齐方式(UILabel没有这个属性),但是把 label 的 frame 高度改小也能实现相同的效果。
如果内容长度超过一行,把numberOfLines设成 0(就是不限制行数)。
有一个问题是,不管你设置了文字是水平居中还是右对齐,那么执行完sizeToFit后 frame 宽度也缩小了,文字会缩到左上角,效果都比较差,如图:
解决方法是把 label 的宽度先用变量保存起来,执行完sizeToFit之后再设回来,就解决了上面的问题,如图:
另外要注意,sizeToFit 会把 label 的当前宽度当做最大宽度,执行之后宽度只会比变窄,不会变宽。
Last but not least! 如果你是使用Auto Layout 的 NIB 和 Storyboard,Mark Amery 在评论中补充了解决方案:
如果 nib 或 storyboard 里用了 autoLayout,那么在viewDidLoad调sizeToFit是不管用的,因为实际顺序是先执行viewDidLoad再执行 autoLayout,执行 autoLayout 的时候会把 sizeToFit 的结果覆盖掉。
不过,在viewDidLayoutSubviews里调sizeToFit是管用的。
一个更简单粗暴的办法,是把UILabel的 “line break mode” 设为 “Clip”,然后直接在末尾加一些换行符。
myLabel.lineBreakMode = UILineBreakModeClip;
myLabel.text = [displayString stringByAppendingString:"\n\n\n\n"];
不过,这个方法不是万能的,当Label文字超出范围并且需要在末尾显示“…”就不行了,不会自动缩略末尾变成“…”。
用UITextField取代UILabel,默认就是顶端对齐的。
同时把userInterationEnabled设为NO,让它不能滚动。
创建一个UILabel的子类,用起来非常方便:
// TopLeftLabel.h
#import
@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
直接上代码…:
#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];
}
但是,出现了第二次滑动到指定位置才有效,并且有奇奇怪怪的效果:
考虑到是cell的重用缓存,以及view的生命周期顺序问题:layoutSubviews方法调用先于drawRect
我要在View绘制子控件时再次确定cell的布局,于是把代码放到drawRect中:
- (void)drawRect:(CGRect)rect{
[self.captionLabel sizeToFit];
[self.containerView clipsToCornerRadius:8];
}
如果还是有问题,可以考虑直接用其他方式,如后来出现有UILabel文字显示不全的现象,最后用方法二代替了~