ios 在 UILabel 中将文本垂直对齐到顶部
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1054558/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Vertically align text to top within a UILabel
提问by Stefan
I have a UILabel
with space for two lines of text. Sometimes, when the text is too short, this text is displayed in the vertical center of the label.
我有UILabel
两行文本的空间。有时,当文本太短时,此文本会显示在标签的垂直中心。
How do I vertically align the text to always be at the top of the UILabel
?
如何垂直对齐文本以始终位于 的顶部UILabel
?
回答by nevan king
There's no way to set the vertical-align on a UILabel
, but you can get the same effect by changing the label's frame. I've made my labels orange so you can see clearly what's happening.
无法在 a 上设置垂直对齐UILabel
,但您可以通过更改标签的框架来获得相同的效果。我已将标签设为橙色,以便您可以清楚地看到发生了什么。
Here's the quick and easy way to do this:
这是执行此操作的快速简便的方法:
[myLabel sizeToFit];
If you have a label with longer text that will make more than one line, set numberOfLines
to 0
(zero here means an unlimited number of lines).
如果您有一个包含更长文本的标签,将超过一行,请设置numberOfLines
为0
(此处为零表示无限行数)。
myLabel.numberOfLines = 0;
[myLabel sizeToFit];
Longer Version
更长的版本
I'll make my label in code so that you can see what's going on. You can set up most of this in Interface Builder too. My setup is a View-Based App with a background image I made in Photoshop to show margins (20 points). The label is an attractive orange color so you can see what's going on with the dimensions.
我将在代码中制作我的标签,以便您可以看到发生了什么。您也可以在 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];
}
Some limitations of using sizeToFit
come into play with center- or right-aligned text. Here's what happens:
使用的一些限制sizeToFit
与居中或右对齐的文本有关。这是发生的事情:
// myLabel.textAlignment = NSTextAlignmentRight;
myLabel.textAlignment = NSTextAlignmentCenter;
[myLabel setNumberOfLines:0];
[myLabel sizeToFit];
The label is still sized with a fixed top-left corner. You can save the original label's width in a variable and set it after sizeToFit
, or give it a fixed width to counter these problems:
标签的大小仍然固定在左上角。您可以将原始标签的宽度保存在一个变量中并将其设置在 之后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;
Note that sizeToFit
will respect your initial label's minimum width. If you start with a label 100 wide and call sizeToFit
on it, it will give you back a (possibly very tall) label with 100 (or a little less) width. You might want to set your label to the minimum width you want before resizing.
请注意,这sizeToFit
将尊重您的初始标签的最小宽度。如果你从一个 100 宽的标签开始并调用sizeToFit
它,它会给你一个 100(或更少)宽度的(可能非常高)标签。在调整大小之前,您可能希望将标签设置为所需的最小宽度。
Some other things to note:
其他一些注意事项:
Whether lineBreakMode
is respected depends on how it's set. NSLineBreakByTruncatingTail
(the default) is ignored after sizeToFit
, as are the other two truncation modes (head and middle). NSLineBreakByClipping
is also ignored. NSLineBreakByCharWrapping
works as usual. The frame width is still narrowed to fit to the rightmost letter.
是否lineBreakMode
受到尊重取决于它是如何设置的。NSLineBreakByTruncatingTail
(默认)在 之后被忽略sizeToFit
,其他两种截断模式(头部和中间)也是如此。NSLineBreakByClipping
也被忽略。NSLineBreakByCharWrapping
照常工作。框架宽度仍然变窄以适合最右边的字母。
Mark Amerygave a fix for NIBs and Storyboards using Auto Layout in the comments:
Mark Amery在评论中使用自动布局修复了 NIB 和故事板:
If your label is included in a nib or storyboard as a subview of the
view
of a ViewController that uses autolayout, then putting yoursizeToFit
call intoviewDidLoad
won't work, because autolayout sizes and positions the subviews afterviewDidLoad
is called and will immediately undo the effects of yoursizeToFit
call. However, callingsizeToFit
from withinviewDidLayoutSubviews
willwork.
如果您的标签作为
view
使用自动布局的 ViewController的子视图包含在笔尖或故事板中,那么将您的sizeToFit
调用放入viewDidLoad
将不起作用,因为自动布局会在viewDidLoad
调用之后调整子视图的大小和位置,并将立即撤消您的效果sizeToFit
称呼。但是,sizeToFit
从内部调用viewDidLayoutSubviews
将起作用。
My Original Answer (for posterity/reference):我的原始答案(供后代/参考):
This uses the NSString
method sizeWithFont:constrainedToSize:lineBreakMode:
to calculate the frame height needed to fit a string, then sets the origin and width.
这使用NSString
方法sizeWithFont:constrainedToSize:lineBreakMode:
来计算适合字符串所需的框架高度,然后设置原点和宽度。
Resize the frame for the label using the text you want to insert. That way you can accommodate any number of lines.
使用要插入的文本调整标签框架的大小。这样您就可以容纳任意数量的行。
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;
回答by Jakob Egger
Set the new text:
myLabel.text = @"Some Text"
Set the
maximum number
of lines to 0 (automatic):myLabel.numberOfLines = 0
Set the frame of the label to the maximum size:
myLabel.frame = CGRectMake(20,20,200,800)
Call
sizeToFit
to reduce the frame size so the contents just fit:[myLabel sizeToFit]
设置新文本:
myLabel.text = @"Some Text"
将
maximum number
行数设置为 0(自动):myLabel.numberOfLines = 0
将标签的边框设置为最大尺寸:
myLabel.frame = CGRectMake(20,20,200,800)
调用
sizeToFit
以减小框架大小,以便内容刚好适合:[myLabel sizeToFit]
The labels frame is now just high and wide enough to fit your text. The top left should be unchanged. I have tested this only with the top left-aligned text. For other alignments, you might have to modify the frame afterward.
标签框架现在刚好足够高和宽以适合您的文本。左上角应该保持不变。我仅使用左上角对齐的文本对此进行了测试。对于其他对齐方式,您可能需要在之后修改框架。
Also, my label has word wrapping enabled.
此外,我的标签启用了自动换行。
回答by Dmitri Sologoubenko
Refering to the extension solution:
参考扩展解决方案:
for(int i=1; i< newLinesToPad; i++)
self.text = [self.text stringByAppendingString:@"\n"];
should be replaced by
应该替换为
for(int i=0; i<newLinesToPad; i++)
self.text = [self.text stringByAppendingString:@"\n "];
Additional space is needed in every added newline, because iPhone UILabels
' trailing carriage returns seems to be ignored :(
每个添加的换行符都需要额外的空间,因为 iPhoneUILabels
的尾随回车似乎被忽略了:(
Similarly, alignBottom should be updated too with a @" \n@%"
in place of "\n@%"
(for cycle initialization must be replaced by "for(int i=0..." too).
类似地,alignBottom 也应该用 a@" \n@%"
代替"\n@%"
(对于循环初始化也必须用“for(int i=0...”代替)进行更新。
The following extension works for me:
以下扩展对我有用:
// -- 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
Then call [yourLabel alignTop];
or [yourLabel alignBottom];
after each yourLabel text assignment.
然后在每个 yourLabel 文本分配之后调用[yourLabel alignTop];
或调用[yourLabel alignBottom];
。
回答by jowie
Just in case it's of any help to anyone, I had the same problem but was able to solve the issue simply by switching from using UILabel
to using UITextView
. I appreciate this isn't for everyone because the functionality is a bit different.
以防万一它对任何人有帮助,我遇到了同样的问题,但只需从 using 切换到 usingUILabel
即可解决问题UITextView
。我很欣赏这并不适合所有人,因为功能有点不同。
If you do switch to using UITextView
, you can turn off all the Scroll View properties as well as User Interaction Enabled... This will force it to act more like a label.
如果您确实切换到使用UITextView
,您可以关闭所有滚动视图属性以及启用用户交互...这将迫使它更像一个标签。
回答by jasongregori
No muss, no fuss
不吵不闹
@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
No muss, no Objective-c, no fuss but Swift 3:
没有麻烦,没有 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
斯威夫特 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)
}
}
回答by BadPirate
Like the answer above, but it wasn't quite right, or easy to slap into code so I cleaned it up a bit. Add this extension either to it's own .h and .m file or just paste right above the implementation you intend to use it:
就像上面的答案一样,但它不太正确,或者很容易插入代码,所以我稍微清理了一下。将此扩展名添加到它自己的 .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
And then to use, put your text into the label, and then call the appropriate method to align it:
然后使用,将您的文本放入标签中,然后调用适当的方法来对齐它:
[myLabel alignTop];
or
或者
[myLabel alignBottom];
回答by Purple Ninja Girl
An even quicker (and dirtier) way to accomplish this is by setting the UILabel's line break mode to "Clip" and adding a fixed amount of newlines.
一种更快(更脏)的方法是将 UILabel 的换行模式设置为“剪辑”并添加固定数量的换行符。
myLabel.lineBreakMode = UILineBreakModeClip;
myLabel.text = [displayString stringByAppendingString:"\n\n\n\n"];
This solution won't work for everyone -- in particular, if you still want to show "..." at the end of your string if it exceeds the number of lines you're showing, you'll need to use one of the longer bits of code -- but for a lot of cases this'll get you what you need.
此解决方案不适用于所有人 - 特别是,如果您仍想在字符串末尾显示“...”,如果它超过了您显示的行数,则需要使用以下方法之一较长的代码位——但在很多情况下,这将满足您的需求。
回答by Baig
回答by ivanzoid
Instead of UILabel
you may use UITextField
which has vertical alignment option:
而不是UILabel
您可以使用UITextField
which 具有垂直对齐选项:
textField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
textField.userInteractionEnabled = NO; // Don't allow interaction
回答by David Greco
I've struggled with this one for a long time and I wanted to share my solution.
我在这个问题上挣扎了很长时间,我想分享我的解决方案。
This will give you a UILabel
that will autoshrink text down to 0.5 scales and vertically center the text. These options are also available in Storyboard/IB.
这会给你一个UILabel
将文本自动缩小到 0.5 比例并垂直居中的文本。这些选项在 Storyboard/IB 中也可用。
[labelObject setMinimumScaleFactor:0.5];
[labelObject setBaselineAdjustment:UIBaselineAdjustmentAlignCenters];