我有一个UILabel
,可以容纳两行文字。有时,当文本太短时,此文本将显示在标签的垂直中心。
如何将文字垂直对齐,始终位于UILabel
?
答案 0 :(得分:2636)
无法在UILabel
上设置垂直对齐,但您可以通过更改标签的框架来获得相同的效果。我把我的标签变成了橙色,这样你就可以清楚地看到发生了什么。
以下是快速简便的方法:
[myLabel sizeToFit];
如果您的文字较长的标签会生成多行,请将numberOfLines
设置为0
(此处为零表示无限数量的行)。
myLabel.numberOfLines = 0;
[myLabel sizeToFit];
更长的版本
我会在代码中制作我的标签,以便您可以看到正在发生的事情。您也可以在Interface Builder中设置大部分内容。我的设置是基于视图的应用程序,带有我在Photoshop中制作的背景图像,以显示边距(20分)。标签是一种诱人的橙色,因此您可以看到尺寸发生了什么。
- (void)viewDidLoad
{
[super viewDidLoad];
// 20 point top and left margin. Sized to leave 20 pt at right.
CGRect labelFrame = CGRectMake(20, 20, 280, 150);
UILabel *myLabel = [[UILabel alloc] initWithFrame:labelFrame];
[myLabel setBackgroundColor:[UIColor orangeColor]];
NSString *labelText = @"I am the very model of a modern Major-General, I've information vegetable, animal, and mineral";
[myLabel setText:labelText];
// Tell the label to use an unlimited number of lines
[myLabel setNumberOfLines:0];
[myLabel sizeToFit];
[self.view addSubview:myLabel];
}
使用sizeToFit
的一些限制与中心对齐或右对齐文本相关。这是发生的事情:
// myLabel.textAlignment = NSTextAlignmentRight;
myLabel.textAlignment = NSTextAlignmentCenter;
[myLabel setNumberOfLines:0];
[myLabel sizeToFit];
标签尺寸仍然是固定的左上角。您可以将原始标签的宽度保存在变量中,并在sizeToFit
之后设置它,或者给它一个固定的宽度来解决这些问题:
myLabel.textAlignment = NSTextAlignmentCenter;
[myLabel setNumberOfLines:0];
[myLabel sizeToFit];
CGRect myFrame = myLabel.frame;
// Resize the frame's width to 280 (320 - margins)
// width could also be myOriginalLabelFrame.size.width
myFrame = CGRectMake(myFrame.origin.x, myFrame.origin.y, 280, myFrame.size.height);
myLabel.frame = myFrame;
请注意,sizeToFit
会尊重您的初始标签的最小宽度。如果您从100宽的标签开始并在其上调用sizeToFit
,它将返回一个(可能非常高)标签,宽度为100(或更小)。您可能希望在调整大小之前将标签设置为所需的最小宽度。
其他一些注意事项:
是否尊重lineBreakMode
取决于它的设置方式。在NSLineBreakByTruncatingTail
之后忽略sizeToFit
(默认值),其他两种截断模式(头部和中间)也是如此。 NSLineBreakByClipping
也被忽略了。 NSLineBreakByCharWrapping
像往常一样工作。框架宽度仍然缩小以适合最右边的字母。
Mark Amery在评论中使用自动布局修复了NIB和故事板:
如果您的标签作为使用自动布局的ViewController
view
的子视图包含在笔尖或故事板中,那么将sizeToFit
调用放入viewDidLoad
将无效,因为在viewDidLoad
被调用后自动布局会调整子视图的大小和位置,并会立即撤消sizeToFit
调用的效果。但是,从sizeToFit
中调用viewDidLayoutSubviews
将工作。
<小时/> 我的原始答案(后代/参考):
这使用NSString
方法sizeWithFont:constrainedToSize:lineBreakMode:
来计算拟合字符串所需的帧高,然后设置原点和宽度。
使用要插入的文本调整标签的框架大小。这样你就可以容纳任意数量的行。
CGSize maximumSize = CGSizeMake(300, 9999);
NSString *dateString = @"The date today is January 1st, 1999";
UIFont *dateFont = [UIFont fontWithName:@"Helvetica" size:14];
CGSize dateStringSize = [dateString sizeWithFont:dateFont
constrainedToSize:maximumSize
lineBreakMode:self.dateLabel.lineBreakMode];
CGRect dateFrame = CGRectMake(10, 10, 300, dateStringSize.height);
self.dateLabel.frame = dateFrame;
答案 1 :(得分:326)
设置新文字:
myLabel.text = @"Some Text"
将行的maximum number
设置为0(自动):
myLabel.numberOfLines = 0
将标签的框架设置为最大尺寸:
myLabel.frame = CGRectMake(20,20,200,800)
调用sizeToFit
减少帧大小,使内容恰好适合:
[myLabel sizeToFit]
现在,标签框架的高度和宽度足以适合您的文字。左上角应保持不变。我只用左上对齐的文本测试了这个。对于其他对齐,您可能必须在之后修改框架。
另外,我的标签启用了自动换行。
答案 2 :(得分:157)
参考扩展解决方案:
for(int i=1; i< newLinesToPad; i++)
self.text = [self.text stringByAppendingString:@"\n"];
应替换为
for(int i=0; i<newLinesToPad; i++)
self.text = [self.text stringByAppendingString:@"\n "];
每个添加的换行符都需要额外的空格,因为似乎忽略了iPhone UILabels
'尾随回车符:(
同样,alignBottom也应该使用@" \n@%"
代替"\n@%"
进行更新(循环初始化必须替换为“for(int i = 0 ...”)。
以下扩展程序适用于我:
// -- file: UILabel+VerticalAlign.h
#pragma mark VerticalAlign
@interface UILabel (VerticalAlign)
- (void)alignTop;
- (void)alignBottom;
@end
// -- file: UILabel+VerticalAlign.m
@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文本分配后调用[yourLabel alignTop];
或[yourLabel alignBottom];
。
答案 3 :(得分:136)
为了防止对任何人有任何帮助,我遇到了同样的问题,但只需从使用UILabel
切换到使用UITextView
就可以解决问题。我很欣赏这并不适合所有人,因为功能有点不同。
如果您切换到使用UITextView
,您可以关闭所有滚动视图属性以及启用用户交互...这将强制它更像标签。
答案 4 :(得分:97)
没有麻烦,没有大惊小怪
@interface MFTopAlignedLabel : UILabel
@end
@implementation MFTopAlignedLabel
- (void)drawTextInRect:(CGRect) rect
{
NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:self.text attributes:@{NSFontAttributeName:self.font}];
rect.size.height = [attributedText boundingRectWithSize:rect.size
options:NSStringDrawingUsesLineFragmentOrigin
context:nil].size.height;
if (self.numberOfLines != 0) {
rect.size.height = MIN(rect.size.height, self.numberOfLines * self.font.lineHeight);
}
[super drawTextInRect:rect];
}
@end
没有muss,没有Objective-c,没有大惊小怪但是Swift 3:
class VerticalTopAlignLabel: UILabel {
override func drawText(in rect:CGRect) {
guard let labelText = text else { return super.drawText(in: rect) }
let attributedText = NSAttributedString(string: labelText, attributes: [NSFontAttributeName: font])
var newRect = rect
newRect.size.height = attributedText.boundingRect(with: rect.size, options: .usesLineFragmentOrigin, context: nil).size.height
if numberOfLines != 0 {
newRect.size.height = min(newRect.size.height, CGFloat(numberOfLines) * font.lineHeight)
}
super.drawText(in: newRect)
}
}
Swift 4.2
class VerticalTopAlignLabel: UILabel {
override func drawText(in rect:CGRect) {
guard let labelText = text else { return super.drawText(in: rect) }
let attributedText = NSAttributedString(string: labelText, attributes: [NSAttributedString.Key.font: font])
var newRect = rect
newRect.size.height = attributedText.boundingRect(with: rect.size, options: .usesLineFragmentOrigin, context: nil).size.height
if numberOfLines != 0 {
newRect.size.height = min(newRect.size.height, CGFloat(numberOfLines) * font.lineHeight)
}
super.drawText(in: newRect)
}
}
答案 5 :(得分:77)
就像上面的答案一样,但它不太正确,或者很容易打入代码,所以我把它清理了一下。将此扩展名添加到它自己的.h和.m文件中,或者只是粘贴到您打算使用它的实现上方:
#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];
答案 6 :(得分:68)
更快(更脏)的方法是将UILabel的换行模式设置为“Clip”并添加固定数量的换行符。
myLabel.lineBreakMode = UILineBreakModeClip;
myLabel.text = [displayString stringByAppendingString:"\n\n\n\n"];
此解决方案不适用于所有人 - 特别是,如果您仍希望在字符串末尾显示“...”,如果它超出您显示的行数,则需要使用较长的代码之一 - 但在很多情况下,这将为您提供所需的功能。
答案 7 :(得分:61)
您可以使用具有垂直对齐选项的UILabel
代替UITextField
:
textField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
textField.userInteractionEnabled = NO; // Don't allow interaction
答案 8 :(得分:49)
我很长时间都在努力解决这个问题,我想分享我的解决方案。
这将为您提供一个UILabel
,它会将文本自动缩小到0.5个刻度并垂直居中显示文本。这些选项也可在Storyboard / IB中找到。
[labelObject setMinimumScaleFactor:0.5];
[labelObject setBaselineAdjustment:UIBaselineAdjustmentAlignCenters];
答案 9 :(得分:43)
创建一个新类
LabelTopAlign
.h文件
#import <UIKit/UIKit.h>
@interface KwLabelTopAlign : UILabel {
}
@end
.m文件
#import "KwLabelTopAlign.h"
@implementation KwLabelTopAlign
- (void)drawTextInRect:(CGRect)rect {
int lineHeight = [@"IglL" sizeWithFont:self.font constrainedToSize:CGSizeMake(rect.size.width, 9999.0f)].height;
if(rect.size.height >= lineHeight) {
int textHeight = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(rect.size.width, rect.size.height)].height;
int yMax = textHeight;
if (self.numberOfLines > 0) {
yMax = MIN(lineHeight*self.numberOfLines, yMax);
}
[super drawTextInRect:CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, yMax)];
}
}
@end
这是一个更简单的实现:
#import "KwLabelTopAlign.h"
@implementation KwLabelTopAlign
- (void)drawTextInRect:(CGRect)rect
{
CGFloat height = [self.text sizeWithFont:self.font
constrainedToSize:rect.size
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];
}
@end
答案 10 :(得分:40)
故事板解决方案:
最简单,最简单的方法是在Label
中嵌入StackView
并将StackView的Axis
设置为Horizontal
,将Alignment
设置为Top
来自故事板的Attribute Inspector
。
答案 11 :(得分:38)
在Interface Builder中
UILabel
设置为最大可能文本的大小Lines
设置为“0”在您的代码中
sizeToFit
代码段:
self.myLabel.text = @"Short Title";
[self.myLabel sizeToFit];
答案 12 :(得分:33)
对于自适应UI(iOS8或之后),通过更改属性从StoryBoard设置UILabel的垂直对齐
ng-if="X && Y != 'blah' && (Z ? true : false)"
= 0`和
<强>约束强>
调整UILabel LefMargin,RightMargin和Top Margin Constraints。
- 醇>
更改
noOfLines
= 1000`以便垂直&gt;水平。
<强>编辑:强>
Content Compression Resistance Priority For Vertical
以下约束足以达到预期效果。
答案 13 :(得分:33)
创建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
正如here所述。
答案 14 :(得分:27)
我写了一个util函数来实现这个目的。你可以看看:
// adjust the height of a multi-line label to make it align vertical with top + (void) alignLabelWithTop:(UILabel *)label { CGSize maxSize = CGSizeMake(label.frame.size.width, 999); label.adjustsFontSizeToFitWidth = NO; // get actual height CGSize actualSize = [label.text sizeWithFont:label.font constrainedToSize:maxSize lineBreakMode:label.lineBreakMode]; CGRect rect = label.frame; rect.size.height = actualSize.height; label.frame = rect; }
。如何使用? (如果lblHello是由Interface builder创建的,那么我会跳过一些UILabel属性的详细信息)
lblHello.text = @"Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!"; lblHello.numberOfLines = 5; [Utils alignLabelWithTop:lblHello];
我也在我的博客上写了一篇文章: http://fstoke.me/blog/?p=2819
答案 15 :(得分:26)
我花了一段时间阅读代码以及介绍页面中的代码,发现他们都试图修改标签的帧大小,这样就不会出现默认的中心垂直对齐。
但是,在某些情况下,我们确实希望标签占据所有这些空格,即使标签确实有这么多文本(例如多行高度相等)。
在这里,我使用另一种方法来解决它,只需将换行符填充到标签的末尾(请注意我实际上继承了UILabel
,但这不是必需的):
CGSize fontSize = [self.text sizeWithFont:self.font];
finalHeight = fontSize.height * self.numberOfLines;
finalWidth = 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 "];
}
答案 16 :(得分:19)
我在这里提出了建议并创建了一个视图,它可以包装UILabel并调整大小并设置行数,使其顶部对齐。只需将UILabel作为子视图:
@interface TopAlignedLabelContainer : UIView
{
}
@end
@implementation TopAlignedLabelContainer
- (void)layoutSubviews
{
CGRect bounds = self.bounds;
for (UILabel *label in [self subviews])
{
if ([label isKindOfClass:[UILabel class]])
{
CGSize fontSize = [label.text sizeWithFont:label.font];
CGSize textSize = [label.text sizeWithFont:label.font
constrainedToSize:bounds.size
lineBreakMode:label.lineBreakMode];
label.numberOfLines = textSize.height / fontSize.height;
label.frame = CGRectMake(0, 0, textSize.width,
fontSize.height * label.numberOfLines);
}
}
}
@end
答案 17 :(得分:16)
您可以使用TTTAttributedLabel,它支持垂直对齐。
@property (nonatomic) TTTAttributedLabel* label;
<...>
//view's or viewController's init method
_label.verticalAlignment = TTTAttributedLabelVerticalAlignmentTop;
答案 18 :(得分:14)
我想要一个能够拥有多行,最小字体大小的标签,并在其父视图中水平和垂直居中。我以编程方式将我的标签添加到我的视图中:
- (void) customInit {
// Setup label
self.label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
self.label.numberOfLines = 0;
self.label.lineBreakMode = UILineBreakModeWordWrap;
self.label.textAlignment = UITextAlignmentCenter;
// Add the label as a subview
self.autoresizesSubviews = YES;
[self addSubview:self.label];
}
然后当我想改变我的标签文本时......
- (void) updateDisplay:(NSString *)text {
if (![text isEqualToString:self.label.text]) {
// Calculate the font size to use (save to label's font)
CGSize textConstrainedSize = CGSizeMake(self.frame.size.width, INT_MAX);
self.label.font = [UIFont systemFontOfSize:TICKER_FONT_SIZE];
CGSize textSize = [text sizeWithFont:self.label.font constrainedToSize:textConstrainedSize];
while (textSize.height > self.frame.size.height && self.label.font.pointSize > TICKER_MINIMUM_FONT_SIZE) {
self.label.font = [UIFont systemFontOfSize:self.label.font.pointSize-1];
textSize = [ticker.blurb sizeWithFont:self.label.font constrainedToSize:textConstrainedSize];
}
// In cases where the frame is still too large (when we're exceeding minimum font size),
// use the views size
if (textSize.height > self.frame.size.height) {
textSize = [text sizeWithFont:self.label.font constrainedToSize:self.frame.size];
}
// Draw
self.label.frame = CGRectMake(0, self.frame.size.height/2 - textSize.height/2, self.frame.size.width, textSize.height);
self.label.text = text;
}
[self setNeedsDisplay];
}
希望能帮助别人!
答案 19 :(得分:14)
我使用了很多上面的方法,只是想添加一个我用过的快速方法:
myLabel.text = [NSString stringWithFormat:@"%@\n\n\n\n\n\n\n\n\n",@"My label text string"];
确保字符串中的换行符数量会导致任何文本填充可用的垂直空间,并将UILabel设置为截断任何溢出的文本。
因为有时足够好足够好。
答案 20 :(得分:14)
我发现这个问题的答案现在有点过时了,所以在那里添加了自动布局粉丝。
自动布局使这个问题变得非常简单。假设我们将标签添加到UIView *view
,以下代码将完成此操作:
UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
[label setText:@"Some text here"];
[label setTranslatesAutoresizingMaskIntoConstraints:NO];
[view addSubview:label];
[view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[label]|" options:0 metrics:nil views:@{@"label": label}]];
[view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[label]" options:0 metrics:nil views:@{@"label": label}]];
标签的高度将自动计算(使用intrinsicContentSize
),标签将水平对齐,位于view
的顶部。
答案 21 :(得分:13)
FXLabel (on github)通过将label.contentMode
设置为UIViewContentModeTop
来实现此功能。这个组件不是由我制作的,但它是我经常使用的组件,具有大量功能,并且似乎运行良好。
答案 22 :(得分:11)
对于阅读此内容的人来说,因为标签内的文字不是垂直居中的,请记住某些字体类型的设计不同。例如,如果您创建一个zapfino大小为16的标签,您将看到文本没有完全垂直居中。
但是,使用helvetica会垂直居中你的文字。
答案 23 :(得分:10)
子类UILabel并约束绘图矩形,如下所示:
- (void)drawTextInRect:(CGRect)rect
{
CGSize sizeThatFits = [self sizeThatFits:rect.size];
rect.size.height = MIN(rect.size.height, sizeThatFits.height);
[super drawTextInRect:rect];
}
我尝试了涉及换行填充的解决方案,并在某些情况下遇到了错误的行为。根据我的经验,如上所述限制绘图矩形比使用numberOfLines
更容易。
P.S。您可以想象以这种方式轻松支持UIViewContentMode:
- (void)drawTextInRect:(CGRect)rect
{
CGSize sizeThatFits = [self sizeThatFits:rect.size];
if (self.contentMode == UIViewContentModeTop) {
rect.size.height = MIN(rect.size.height, sizeThatFits.height);
}
else if (self.contentMode == UIViewContentModeBottom) {
rect.origin.y = MAX(0, rect.size.height - sizeThatFits.height);
rect.size.height = MIN(rect.size.height, sizeThatFits.height);
}
[super drawTextInRect:rect];
}
答案 24 :(得分:10)
如果您使用的是自动布局,请在代码或IB中将垂直contentHuggingPriority设置为1000。在IB中,您可能必须通过将其优先级设置为1来删除高度约束,然后将其删除。
答案 25 :(得分:9)
答案 26 :(得分:8)
使用textRect(forBounds:limitedToNumberOfLines:)
。
class TopAlignedLabel: UILabel {
override func drawText(in rect: CGRect) {
let textRect = super.textRect(forBounds: bounds, limitedToNumberOfLines: numberOfLines)
super.drawText(in: textRect)
}
}
答案 27 :(得分:7)
只要您没有执行任何复杂任务,就可以使用UITextView
代替UILabels
。
禁用滚动。
如果您希望完全显示文字只需用户sizeToFit
和sizeThatFits:
方法
答案 28 :(得分:7)
在swift中,
let myLabel : UILabel!
使您的标签文字适合屏幕,它位于顶部
myLabel.sizeToFit()
使标签字体适合屏幕宽度或特定宽度尺寸。
myLabel.adjustsFontSizeToFitWidth = YES
和标签的一些textAlignment:
myLabel.textAlignment = .center
myLabel.textAlignment = .left
myLabel.textAlignment = .right
myLabel.textAlignment = .Natural
myLabel.textAlignment = .Justified
答案 29 :(得分:6)
如果您可以选择创建自己的自定义视图,则可以执行以下操作:
- (void)drawRect:(CGRect)rect
{
CGRect bounds = self.bounds;
[self.textColor set];
[self.text drawInRect:bounds
withFont:self.font
lineBreakMode:UILineBreakModeTailTruncation
alignment:self.textAlignment];
}
答案 30 :(得分:6)
我知道这是一个旧帖子,但垂直对齐文本是一个巨大的问题(至少对我来说是这样),我想我应该分享这个解决方案,因为我自己找不到一个。
在我看来,使用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:
将被调用,然后您可以计算偏移大小以适当地对齐文本。
我不能相信这一点,最初的想法来自here。但是,这个解决方案在iOS7上不起作用。在SO周围拖了几个小时之后,我发现了这个:iOS 7 vertical alignment fix。关键线是contentheight = [tv sizeThatFits:CGSizeMake(tv.frame.size.width, FLT_MAX)].height;
。出于某种原因,在iOS 7中,获取contentSize高度不起作用,但修复了它。这两种解决方案都不能单独工作,但经过一点修修补补后,我能够将上述解决方案合成在一起。
答案 31 :(得分:6)
这是一个旧解决方案,在iOS上使用autolayout&gt; = 6
我的解决方案:
1 /我自己分割线(忽略标签包装设置)
2 /自己画线(忽略标签对齐)
@interface UITopAlignedLabel : UILabel
@end
@implementation UITopAlignedLabel
#pragma mark Instance methods
- (NSArray*)splitTextToLines:(NSUInteger)maxLines {
float width = self.frame.size.width;
NSArray* words = [self.text componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSMutableArray* lines = [NSMutableArray array];
NSMutableString* buffer = [NSMutableString string];
NSMutableString* currentLine = [NSMutableString string];
for (NSString* word in words) {
if ([buffer length] > 0) {
[buffer appendString:@" "];
}
[buffer appendString:word];
if (maxLines > 0 && [lines count] == maxLines - 1) {
[currentLine setString:buffer];
continue;
}
float bufferWidth = [buffer sizeWithFont:self.font].width;
if (bufferWidth < width) {
[currentLine setString:buffer];
}
else {
[lines addObject:[NSString stringWithString:currentLine]];
[buffer setString:word];
[currentLine setString:buffer];
}
}
if ([currentLine length] > 0) {
[lines addObject:[NSString stringWithString:currentLine]];
}
return lines;
}
- (void)drawRect:(CGRect)rect {
if ([self.text length] == 0) {
return;
}
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, self.textColor.CGColor);
CGContextSetShadowWithColor(context, self.shadowOffset, 0.0f, self.shadowColor.CGColor);
NSArray* lines = [self splitTextToLines:self.numberOfLines];
NSUInteger numLines = [lines count];
CGSize size = self.frame.size;
CGPoint origin = CGPointMake(0.0f, 0.0f);
for (NSUInteger i = 0; i < numLines; i++) {
NSString* line = [lines objectAtIndex:i];
if (i == numLines - 1) {
[line drawAtPoint:origin forWidth:size.width withFont:self.font lineBreakMode:UILineBreakModeTailTruncation];
}
else {
[line drawAtPoint:origin forWidth:size.width withFont:self.font lineBreakMode:UILineBreakModeClip];
}
origin.y += self.font.lineHeight;
if (origin.y >= size.height) {
return;
}
}
}
@end
答案 32 :(得分:6)
在UILabel中,垂直文本对齐是不可能的。但是,您可以使用sizeWithFont:
的{{1}}方法动态更改标签的高度,并根据需要设置其x和y。
您可以使用NSString
。它支持 contentVerticalAlignment peoperty ,因为它是UITextField
的子类。您必须将其UIControl
设置为NO以防止用户在其上键入文本。
答案 33 :(得分:5)
我也在研究这个特定的问题,所以我采用了 DS 和 nevan king 的想法,基本上将它们组合成一个实现垂直的子类alignment属性,它还允许您更改对齐不止一次。它借用UIControlContentVerticalAlignment
类型并支持UIControlContentVerticalAlignmentFill
。
从我所看到的情况来看,numberOfLines
在垂直对齐方面似乎毫无用处,因此在应用垂直对齐时,在此子类中始终设置为0。
此外,您还需要自己设置lineBreakMode
以防万一您需要多行文字标签。
答案 34 :(得分:5)
我对dalewking的建议感到不满,并添加了一个UIEdgeInset以允许可调整的边距。好好的工作。
- (id)init
{
if (self = [super init]) {
contentEdgeInsets = UIEdgeInsetsZero;
}
return self;
}
- (void)layoutSubviews
{
CGRect localBounds = self.bounds;
localBounds = CGRectMake(MAX(0, localBounds.origin.x + contentEdgeInsets.left),
MAX(0, localBounds.origin.y + contentEdgeInsets.top),
MIN(localBounds.size.width, localBounds.size.width - (contentEdgeInsets.left + contentEdgeInsets.right)),
MIN(localBounds.size.height, localBounds.size.height - (contentEdgeInsets.top + contentEdgeInsets.bottom)));
for (UIView *subview in self.subviews) {
if ([subview isKindOfClass:[UILabel class]]) {
UILabel *label = (UILabel*)subview;
CGSize lineSize = [label.text sizeWithFont:label.font];
CGSize sizeForText = [label.text sizeWithFont:label.font constrainedToSize:localBounds.size lineBreakMode:label.lineBreakMode];
NSInteger numberOfLines = ceilf(sizeForText.height/lineSize.height);
label.numberOfLines = numberOfLines;
label.frame = CGRectMake(MAX(0, contentEdgeInsets.left), MAX(0, contentEdgeInsets.top), localBounds.size.width, MIN(localBounds.size.height, lineSize.height * numberOfLines));
}
}
}
答案 35 :(得分:5)
Swift 2.0:
在空的Swift文件中创建常量枚举值。
// AppRef.swift
import UIKit
import Foundation
enum UILabelTextPositions : String {
case VERTICAL_ALIGNMENT_TOP = "VerticalAlignmentTop"
case VERTICAL_ALIGNMENT_MIDDLE = "VerticalAlignmentMiddle"
case VERTICAL_ALIGNMENT_BOTTOM = "VerticalAlignmentBottom"
}
使用UILabel扩展:
创建一个空的Swift类并命名它。添加以下
// AppExtensions.swift
import Foundation
import UIKit
extension UILabel{
func makeLabelTextPosition (sampleLabel :UILabel?, positionIdentifier : String) -> UILabel
{
let rect = sampleLabel!.textRectForBounds(bounds, limitedToNumberOfLines: 0)
switch positionIdentifier
{
case "VerticalAlignmentTop":
sampleLabel!.frame = CGRectMake(bounds.origin.x+5, bounds.origin.y, rect.size.width, rect.size.height)
break;
case "VerticalAlignmentMiddle":
sampleLabel!.frame = CGRectMake(bounds.origin.x+5,bounds.origin.y + (bounds.size.height - rect.size.height) / 2,
rect.size.width, rect.size.height);
break;
case "VerticalAlignmentBottom":
sampleLabel!.frame = CGRectMake(bounds.origin.x+5, bounds.origin.y + (bounds.size.height - rect.size.height),rect.size.width, rect.size.height);
break;
default:
sampleLabel!.frame = bounds;
break;
}
return sampleLabel!
}
}
用法:
myMessageLabel.makeLabelTextPosition(messageLabel, positionIdentifier: UILabelTextPositions.VERTICAL_ALIGNMENT_TOP.rawValue)
答案 36 :(得分:4)
yourLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters;
答案 37 :(得分:4)
有两种方法可以解决这个问题。一个是
[mylabel setNumberOfLines:0];
[mylabel sizeToFit];
但第二种方法对于这种方法更可靠,即
CGSize sizeToFit = [label.text sizeWithFont:label.font constrainedToSize:maxSize lineBreakMode:label.lineBreakMode];
[mylabel setFrame:CGRectMake(mylabel.frame.origin.x, mylabel.frame.origin.y, sizeToFit.width, sizeToFit.height)];
输入“\ n”并不是一件好事,但如果您知道要显示的数据的约束和大小,则可能是正常工作但如果文本长度大于标签大小则无法扩展。第二种方式最终根据要显示的文本大小设置框架。
答案 38 :(得分:4)
对于Swift 3 ......
@IBDesignable class TopAlignedLabel: UILabel {
override func drawText(in rect: CGRect) {
if let stringText = text {
let stringTextAsNSString = stringText as NSString
let labelStringSize = stringTextAsNSString.boundingRect(with: CGSize(width: self.frame.width,height: CGFloat.greatestFiniteMagnitude),
options: NSStringDrawingOptions.usesLineFragmentOrigin,
attributes: [NSFontAttributeName: font],
context: nil).size
super.drawText(in: CGRect(x:0,y: 0,width: self.frame.width, height:ceil(labelStringSize.height)))
} else {
super.drawText(in: rect)
}
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
layer.borderWidth = 1
layer.borderColor = UIColor.black.cgColor
}
}
答案 39 :(得分:3)
此代码可帮助您将文本对齐到顶部,并使标签高度固定为文本内容。
使用以下代码的说明
默认情况下, isHeightToChange
为true会使标签的高度自动与文本内容相同。
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
答案 40 :(得分:3)
(截至2018年3月7日)
Swift 4
let maxFrameHeight = 75
myLabel = UILabel()
myLabel.frame = CGRect(x: 9, y: 9, width: 126, height: maxFrameHeight)
myLabel.text = "my labels text displayed"
myLabel.numberOfLines = 0
myLabel.sizeToFit()
let newFrameHeight = myLabel.frame.size.height
let safeNewHeight = min(newFrameHeight, maxFrameHeight)
myLabel.frame = CGRect(x: 9, y: 9, width: 126, height: safeNewHeight)
这将获得理想的结果,并确保UILabel的新高度不会超过您对此标签所需的最大高度。
答案 41 :(得分:3)
对于那些尝试修复此问题的自定义表格单元格的人,请将其添加到自定义表格单元格类中:
Swift 2.2:
override func layoutSubviews() {
labelName.sizeToFit()
}
这解决了我的问题。
答案 42 :(得分:3)
您可以手动更改标签的高度,而不是使用sizeToFit
;
CGSize size = [descLabel.text sizeWithFont:descLabel.font constrainedToSize:CGSizeMake(labelWidth, labelHeight)];
CGRect frame = descLabel.frame;
frame.size.height = size.height;
[yourLabel setFrame:frame];
返回的尺寸最适合您标签的内容。如果标签的高度适合其内容,则不会出现位于标签中心的内容问题。
答案 43 :(得分:2)
在发布的所有其他解决方案的基础上,我创建了一个简单的小UILabel子类,在设置其alignment属性时将为您处理垂直对齐。这也将更新方向更改时的标签,将文本的高度限制在一起,并将标签的宽度保持为原始大小。
.h
@interface VAlignLabel : UILabel
@property (nonatomic, assign) WBZVerticalAlignment alignment;
@end
.m
-(void)setAlignment:(WBZVerticalAlignment)alignment{
_alignment = alignment;
CGSize s = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(self.frame.size.width, 9999) lineBreakMode:NSLineBreakByWordWrapping];
switch (_alignment)
{
case wbzLabelAlignmentVerticallyTop:
self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, s.height);
break;
case wbzLabelAlignmentVerticallyMiddle:
self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y + (self.frame.size.height - s.height)/2, self.frame.size.width, s.height);
break;
case wbzLabelAlignmentVerticallyBottom:
self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y + (self.frame.size.height - s.height), self.frame.size.width, s.height);
break;
default:
break;
}
}
-(void)layoutSubviews{
[self setAlignment:self.alignment];
}
答案 44 :(得分:1)
解决这个问题的简单方法......
在标签旁边放置一个UIStackView
。
然后使用AutoLayout将标签的垂直间距设置为零,并将顶部约束到之前标签底部。这个标签不会增长,stackView会。我喜欢这个是堆栈视图是非渲染。所以它并没有真正浪费时间渲染。即使它进行AutoLayout计算。
你可能需要使用ContentHugging和Resistance,但这也很简单。
偶尔我会谷歌这个问题并回到这里。这次我有一个我认为最简单的想法,而且我认为它的表现并不好。 我必须说我只是使用AutoLayout并且不想打扰计算帧。那只是......哎呀。
答案 45 :(得分:1)
在SwiftUI中,所有视图通常都是 sizeToFit 内容,但是如果您明确使用frame
修饰符,则可以使用框架的alignment
参数:
Text("Text")
.background(Color.red)
.frame(width: 100, height: 200, alignment: .top)
此外,如果您使用任何类型的Stack
来排列视图,则所有视图都有一个类似于frame的参数,称为alignment
:
ZStack(alignment: .top) {
Color.red
Text("Text")
.background(Color.red)
}
答案 46 :(得分:0)
这是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
}
答案 47 :(得分:0)
可以更灵活地完成此操作,在Interface Builder中将height constraint
设置为标签,使用IBOutlet将其绑定到代码,然后更改该高度以在具体的垂直位置显示文本。中心和底部对齐的示例:
labelHeightConstraint.constant = centerAlignment ? 30 : 15
layoutIfNeeded()
答案 48 :(得分:0)
这里是从左上角开始渲染文本,并保持可能调整的文本大小。
final class TopAlignedLabel: UILabel {
override func drawText(in rect: CGRect) {
super.drawText(in: .init(
origin: .zero,
size: textRect(
forBounds: rect,
limitedToNumberOfLines: numberOfLines
).size
))
}
}
答案 49 :(得分:-1)
试试这个!!太手动,但对我来说非常适合。
[labelName setText:@"This is just a demo"];
NSMutableString *yourString1= @"This is just a demo";
// breaking string
labelName.lineBreakMode=UILineBreakModeTailTruncation;
labelName.numberOfLines = 3;
CGSize maximumLabelSize1 = CGSizeMake(276,37); // Your Maximum text size
CGSize expectedLabelSize1 = [yourString1 sizeWithFont:labelName.font
constrainedToSize:maximumLabelSize1
lineBreakMode:labelName.lineBreakMode];
[labelName setText:yourString1];
CGRect newFrame1 = labelName.frame;
if (expectedLabelSize1.height>=10)
{
newFrame1.size.height = expectedLabelSize1.height;
}
labelName.frame = newFrame1;