我有一个UILabel,它有两行文字的空间。有时,当文本太短时,此文本会显示在标签的垂直中心。

如何垂直对齐文本,使其始终位于UILabel的顶部?


当前回答

可以更灵活地在Interface Builder中为标签设置高度约束,使用IBOutlet将其绑定到代码,并更改高度以在具体的垂直位置显示文本。中心和底部对齐示例:

labelHeightConstraint.constant = centerAlignment ? 30 : 15
layoutIfNeeded()

其他回答

此代码帮助您使文本与顶部对齐,并使标签高度与文本内容固定。

使用以下代码的说明

默认情况下,isHeightToChange会自动将标签的高度设置为与文本内容相同。isHeightToChange如果为false,则使文本对齐到顶部,而不降低标签的高度。

#import "DynamicHeightLable.h"

@implementation DynamicHeightLable
@synthesize isHeightToChange;
- (id)initWithFrame:(CGRect)frame 
{
    self = [super initWithFrame:frame];
    if (self)
    {
        // Initialization code.
        self.isHeightToChange=FALSE;//default

    }
    return self;
}
- (void)drawTextInRect:(CGRect)rect
{
    if(!isHeightToChange){
    CGSize maximumLabelSize = CGSizeMake(self.frame.size.width,2500);

    CGFloat height = [self.text sizeWithFont:self.font
                           constrainedToSize:maximumLabelSize
                               lineBreakMode:self.lineBreakMode].height;
    if (self.numberOfLines != 0) {
        height = MIN(height, self.font.lineHeight * self.numberOfLines);
    }
    rect.size.height = MIN(rect.size.height, height);
    }
    [super drawTextInRect:rect];

}
- (void) layoutSubviews
{
    [super layoutSubviews];
       if(isHeightToChange){
     CGRect ltempFrame = self.frame;
    CGSize maximumLabelSize = CGSizeMake(self.frame.size.width,2500);

    CGFloat height = [self.text sizeWithFont:self.font
                           constrainedToSize:maximumLabelSize
                               lineBreakMode:self.lineBreakMode].height;
    if (self.numberOfLines != 0) {
        height = MIN(height, self.font.lineHeight * self.numberOfLines);
    }
    ltempFrame.size.height = MIN(ltempFrame.size.height, height);

    ltempFrame.size.height=ltempFrame.size.height;
    self.frame=ltempFrame;
       }
}
@end

我知道这是一篇旧文章,但垂直对齐文本是一个巨大的问题(至少对我来说是这样),我想我应该分享这个解决方案,因为我自己找不到。

在我看来,使用drawRect有点贵。使UILabel垂直对齐的正确方法是不使用UILabel。使用UITextView(多行UITextField)并观察内容属性,如下所示:

- (UITextView*)textView{
     if(!_textView){
        UIEdgeInsets insets = UIEdgeInsetsMake(0, 50, 0, 5);
        CGRect frame = CGRectMake(0.0f, 0.0f, 100.0f, 100.0f);
        _textView = [[UITextView alloc]initWithFrame:UIEdgeInsetsInsetRect(frame, insets)];
        _textView.delegate = self;
        _textView.scrollEnabled = YES;
        _textView.bounces = YES;
        _textView.backgroundColor = [UIColor whiteColor];
        [_textView setUserInteractionEnabled:NO];
        [_textView addObserver:self forKeyPath:@"contentSize" options:(NSKeyValueObservingOptionNew) context:NULL];
    }
    return _textView;
}

 -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:    (NSDictionary *)change context:(void *)context {
UITextView *tv = object;

CGFloat height = [tv bounds].size.height;
CGFloat contentheight;

#ifdef __IPHONE_7_0
    contentheight = [tv sizeThatFits:CGSizeMake(tv.frame.size.width, FLT_MAX)].height;
#else
    contentheight = [tv contentSize].height;
#endif

    switch(self.verticalAlignment) {
        case VerticalAlignmentBottom:{
            CGFloat topCorrect = ([tv bounds].size.height - contentheight);
            topCorrect = (topCorrect <0.0 ? 0.0 : topCorrect);
            tv.contentOffset = (CGPoint){.x = 0, .y = -topCorrect};
        }
        break;
        case VerticalAlignmentMiddle:{
            CGFloat topCorrect = (height - contentheight * [tv zoomScale])/2.0;
            topCorrect = ( topCorrect < 0.0 ? 0.0 : topCorrect );
            tv.contentOffset = (CGPoint){.x = 0, .y = -topCorrect};
        }
            break;
        case VerticalAlignmentTop:{
            tv.contentOffset = (CGPoint){.x = 0, .y = 0 };
        }
            break;
        default:
            break;
    }
}

基本上,这里发生的是我们将我们所处的类设置为观察者,使用NSKeyValueObservingOptionNew选项查看contentSize属性,因此每次内容更改时,都会调用-(void)observeValueForKeyPath:ofObject:change:context:,然后您可以计算偏移量大小以适当对齐文本。

我不能把这归功于此,最初的想法来自这里。但是,该解决方案在iOS7上不起作用。在SO周围转了几个小时后,我发现了这个:iOS 7垂直对齐修复。其中的关键行是contentheight=[tv sizeThatFits:CGSizeMake(tv.frame.size.width,FLT_MAX)].height;。由于某种原因,在iOS 7中,获取contentSize高度不起作用,但这可以解决问题。这两个解决方案都不能单独工作,但经过一点修改后,我能够将上述解决方案合成在一起。

Swift 4.0中有一个解决方案:

func viewDidLoad() {

    super.viewDidLoad()

    // 20 point top and left margin. Sized to leave 20 pt at right.
    let labelFrame = CGRect(x: 20, y: 20, width: 280, height: 150)
    let myLabel = UILabel(frame: labelFrame)
    myLabel.backgroundColor = UIColor.orange

    let labelText = "I am the very model of a modern Major-General, 
    I've information vegetable, animal, and mineral"
    myLabel.text = labelText

    // Tell the label to use an unlimited number of lines
    myLabel.numberOfLines = 0
    myLabel.sizeToFit()

    view.addSubview(myLabel) // add label
}

一种更快(更脏)的方法是将UILabel的换行模式设置为“Clip”并添加固定数量的换行符。

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

这种解决方案不适用于所有人——特别是,如果您仍然希望在字符串末尾显示“…”,如果它超过了您要显示的行数,则需要使用较长的代码段之一——但在很多情况下,这将满足您的需要。

FXLabel(在github上)通过将label.contentMode设置为UIViewContentModeTop来实现这一点。这个组件不是我制造的,但它是我经常使用的组件,具有大量的功能,而且似乎工作得很好。