私は2行のテキストのためのスペースを持つUILabel
を持っています。テキストが短すぎる場合は、このテキストがラベルの垂直方向の中央に表示されることがあります。
テキストを常にUILabel
の一番上になるように垂直方向に揃える方法
UILabel
に垂直方向の配置を設定する方法はありませんが、ラベルのフレームを変更しても同じ効果が得られます。ラベルをオレンジ色にしたので、何が起こっているのかがはっきりわかります。
これを行うための迅速で簡単な方法は次のとおりです。
[myLabel sizeToFit];
複数行になる長いテキストのラベルがある場合は、numberOfLines
を0
に設定します(ここでのゼロは無制限の行数を意味します)。
myLabel.numberOfLines = 0;
[myLabel sizeToFit];
長いバージョン
何が起こっているのかわかるように、ラベルをコードにします。このほとんどをInterface Builderでも設定できます。私のセットアップは、私がマージン(20ポイント)を表示するためにPhotoshopで作った背景画像を持つView Based Appです。ラベルは魅力的なオレンジ色なので、寸法を見ればわかります。
- (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
が尊重されるかどうかは、設定方法によって異なります。他の2つの切り捨てモード(headとmiddle)と同様に、NSLineBreakByTruncatingTail
(デフォルト)はsizeToFit
の後で無視されます。 NSLineBreakByClipping
も無視されます。 NSLineBreakByCharWrapping
は通常どおり動作します。枠の幅は、右端の文字に合うように狭くなっています。
Mark Amery はコメントに自動レイアウトを使用してNIBとストーリーボードを修正しました。
自動レイアウトを使用するViewControllerの
view
のサブビューとしてラベルがペン先またはストーリーボードに含まれている場合、sizeToFit
呼び出しをviewDidLoad
に設定しても機能しません。viewDidLoad
が呼び出された後にサブビューを配置し、すぐにsizeToFit
呼び出しの効果を元に戻します。ただし、sizeToFit
will内からviewDidLayoutSubviews
を呼び出すことは機能します。
これはNSString
メソッドsizeWithFont:constrainedToSize:lineBreakMode:
を使って文字列に合わせるのに必要なフレームの高さを計算してから、Originとwidthを設定します。
挿入するテキストを使用してラベルの枠のサイズを変更します。そうすれば、何行にでも対応できます。
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;
新しいテキストを設定します。
myLabel.text = @"Some Text"
行のmaximum number
を0(自動)に設定します。
myLabel.numberOfLines = 0
ラベルの枠を最大サイズに設定します。
myLabel.frame = CGRectMake(20,20,200,800)
内容がぴったり収まるようにフレームサイズを小さくするにはsizeToFit
を呼び出します。
[myLabel sizeToFit]
ラベルフレームはテキストのサイズに合うように高さと幅が調整されています。左上は変更されません。私はこれを左上揃えのテキストでのみテストしました。他の配置では、後でフレームを修正する必要があるかもしれません。
また、私のラベルではワードラップが有効になっています。
拡張ソリューションを参照してください。
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
次に、yourLabelの各テキスト割り当ての後に[yourLabel alignTop];
または[yourLabel alignBottom];
を呼び出します。
大騒ぎも大騒ぎも
@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
大したことも、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)
}
}
上の答えのように、しかしそれは完全には正しくなかった、またはコードにたたくのは簡単ではなかったので、私はそれを少し片付けました。この拡張子をそれ自身の.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];
これを達成するためのさらに速く(そしてより汚い)方法は、UILabelの改行モードを "Clip"に設定し、固定量の改行を追加することです。
myLabel.lineBreakMode = UILineBreakModeClip;
myLabel.text = [displayString stringByAppendingString:"\n\n\n\n"];
この解決法はすべての人にとってうまくいくわけではありません。特に、表示する行数を超えている場合でも、文字列の末尾に "..."を表示する場合は、長いコード - しかし多くの場合、これはあなたが必要なものを手に入れるでしょう。
UILabel
の代わりに、垂直方向の整列オプションを持つUITextField
を使用することができます。
textField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
textField.userInteractionEnabled = NO; // Don't allow interaction
私は長い間これと闘ってきました、そして私は私の解決策を共有したいと思いました。
これはあなたに0.5スケールまでテキストを自動的に縮小し、テキストを垂直方向に中央寄せするUILabel
を与えるでしょう。これらのオプションはStoryboard/IBでも利用できます。
[labelObject setMinimumScaleFactor:0.5];
[labelObject setBaselineAdjustment:UIBaselineAdjustmentAlignCenters];
新しいクラスを作る
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
Interface Builderで
UILabel
を可能な限り大きいテキストのサイズに設定しますLines
を '0'に設定しますあなたのコードで
sizeToFit
を呼び出しますコードスニペット:
self.myLabel.text = @"Short Title";
[self.myLabel sizeToFit];
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
議論したように ここ 。
この目的を達成するためにutil関数を書きました。あなたは見てみることができます:
//複数行のラベルの高さを調整して、垂直方向にtop +(void)alignLabelWithTop:(UILabel *)label { CGSize maxSize = CGSizeMake() label.frame.size.width、999); label.adjustsFontSizeToFitWidth = NO; //実際の高さを取得 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 = @ "ハローワールド!ハローワールド!ハローワールド!ハローワールド!ハローワールド!ハローワールド!ハローワールド!」; lblHello.numberOfLines = 5; [。 [Util.alignLabelWithTop:lblHello];
私は記事としてそれを私のブログにも書いた: http://fstoke.me/blog/?p=2819
紹介されているページのコードと同様にコードを読むのにしばらく時間がかかりました、そして、彼ら全員がラベルのフレームサイズを修正しようとしているので、デフォルトの中央の垂直方向の整列は現れないでしょう。
ただし、場合によっては、ラベルに大量のテキストが含まれていても(たとえば、高さが等しい複数の行など)、ラベルがこれらのスペースすべてを占めるようにしたいことがあります。
ここで、私はそれを解決するために代わりの方法を使いました、単にラベルの終わりまで改行を詰めることによって(plsは私が実際に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 "];
}
私はここで提案を取り、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
TTTAttributedLabel を使うことができます。
@property (nonatomic) TTTAttributedLabel* label;
<...>
//view's or viewController's init method
_label.verticalAlignment = TTTAttributedLabelVerticalAlignmentTop;
私はこの質問に対する答えが少し古くなっているのを発見したので、自動レイアウトファンのためにこれを追加します。
自動レイアウトはこの問題をかなり簡単にします。ラベルを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
の上部に水平方向に配置されます。
私は、複数行、最小フォントサイズ、そして親ビューの水平方向と垂直方向の両方の中央に配置できるラベルを作成したいと思いました。プログラムで自分のラベルを自分のビューに追加しました。
- (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];
}
誰かに役立つことを願っています!
私は上記の多くの方法を使ってきました、そして私が使った簡単なアプローチを加えたいだけです:
myLabel.text = [NSString stringWithFormat:@"%@\n\n\n\n\n\n\n\n\n",@"My label text string"];
文字列内の改行の数によって、テキストが使用可能な垂直方向のスペースを埋めるようにし、UILabelを設定してオーバーフローしたテキストを切り捨てます。
十分に良い場合があるので 十分に良い 。
FXLabel(github上)label.contentMode
をUIViewContentModeTop
に設定することで、そのまま使用できます。このコンポーネントは私が作成したものではありませんが、私がよく使うコンポーネントで、たくさんの機能があり、うまく機能しているようです。
ラベル内のテキストが縦方向に中央揃えされていないため、これを読む人のために、フォントの種類によってはデザインが等しくないことに注意してください。たとえば、サイズが16のzapfinoのラベルを作成すると、テキストは垂直方向の中央に配置されません。
ただし、helveticaを使用すると、テキストが縦方向に中央揃えになります。
自動レイアウトを使用している場合は、コードまたはIBのいずれかでvertical contentHuggingPriorityを1000に設定します。 IBでは、優先度を1に設定してから削除することで、高さの制約を削除する必要があります。
次のように、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];
}
スウィフトでは、
let myLabel : UILabel!
ラベルのテキストを画面に合わせて最上部に表示する
myLabel.sizeToFit()
ラベルのフォントを画面の幅または特定の幅のサイズに合うようにします。
myLabel.adjustsFontSizeToFitWidth = YES
そしてlabelのtextAlignment:
myLabel.textAlignment = .center
myLabel.textAlignment = .left
myLabel.textAlignment = .right
myLabel.textAlignment = .Natural
myLabel.textAlignment = .Justified
複雑な作業をしていない限り、UITextView
の代わりにUILabels
を使用できます。
スクロールを無効にします。
テキストを完全に表示したい場合は、ユーザーのsizeToFit
メソッドとsizeThatFits:
メソッドだけを使用してください。
textRect(forBounds:limitedToNumberOfLines:)
を使用してください。
class TopAlignedLabel: UILabel {
override func drawText(in rect: CGRect) {
let textRect = super.textRect(forBounds: bounds, limitedToNumberOfLines: numberOfLines)
super.drawText(in: textRect)
}
}
これは古い解決策です、iOSの自動レイアウトを使用してください> = 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
UILabelでは、垂直方向のテキスト配置はできません。しかし、NSString
のsizeWithFont:
メソッドを使用してラベルの高さを動的に変更し、必要に応じてそのxとyを設定するだけです。
UITextField
を使うことができます。これはUIControl
のサブクラスであるため、 contentVerticalAlignment peoperty をサポートします。ユーザーがテキストを入力できないようにするには、userInteractionEnabled
をNOに設定する必要があります。
独自のカスタムビューを作成することが選択肢である場合は、次のようにします。
- (void)drawRect:(CGRect)rect
{
CGRect bounds = self.bounds;
[self.textColor set];
[self.text drawInRect:bounds
withFont:self.font
lineBreakMode:UILineBreakModeTailTruncation
alignment:self.textAlignment];
}
これは古い投稿だと思いますが、テキストを垂直方向に整列させることは(少なくとも私にとっては)大きな問題です。自分で見つけることができなかったので、この解決策を共有するべきだと考えました。
DrawRectを使用することは私の意見では少し高価です。 UILabelを垂直方向に整列させる適切な方法は、UILabelを使用しないことです。 UITextView(複数行のUITextField)を使用して、contentプロパティを次のように観察します。
- (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:
が呼び出され、オフセットサイズを計算できますテキストを適切に配置します。
私はこれを信用することはできません、元のアイデアは ここから来ました 。しかし、このソリューションはiOS 7では機能しません。数時間SOを見回した後、私はこれを見つけました: iOS 7の垂直方向の配置の修正 。重要な行はcontentheight = [tv sizeThatFits:CGSizeMake(tv.frame.size.width, FLT_MAX)].height;
です。 iOS 7では、何らかの理由でcontentSizeの高さを取得しても機能しませんが、修正されています。 2つの解決策はどちらも単独では機能しませんでしたが、少し手を加えた後、私は上記の解決策を合成することができました。
yourLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters;
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 Extensionを使う:
空の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)
私はその特定の問題にも取り組んでいたので、 DS と nevan king という考えを取り、基本的にそれらを垂直方向の整列プロパティを実装するサブクラスにまとめました。配置を1回以上変更できます。これはUIControlContentVerticalAlignment
型を借用し、UIControlContentVerticalAlignmentFill
もサポートします。
これまで見てきたことから、numberOfLines
は垂直方向の配置に関しては役に立たないと思われるので、このサブクラスでは垂直方向の配置を適用するときは常に0に設定されます。複数行のテキストラベルが必要な場合はlineBreakMode
自分自身。
そこにあります: GitHub上のQALabel
私は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));
}
}
}
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
}
}
この問題を解決するには2つの方法があります。
[mylabel setNumberOfLines:0];
[mylabel sizeToFit];
しかし、2番目の方法は、この方法ではより信頼性があります。
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"を入力するのはそんなに良いことではありませんが、表示されるデータの制約やサイズがわかっていれば問題ありませんが、テキストがラベルのサイズより長い場合は拡張できません。 2番目の方法は、表示されるテキストのサイズに応じて最終的にフレームを設定します。
このコードは、テキストを上に揃えたり、ラベルの高さを調整してテキストコンテンツを固定したりするのに役立ちます。
以下のコードを使用する指示
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
この問題を解決しようとしているカスタムテーブルセルをお持ちの方は、これをカスタムテーブルセルクラスに追加してください。
Swift 2.2:
override func layoutSubviews() {
labelName.sizeToFit()
}
これで私の問題は解決しました。
(2018年3月7日現在)
スイフト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の新しい高さがあなたがこのラベルのために望むある最大の高さを通過しないことを確かにするでしょう。
sizeToFit
を使用する代わりに、手動でラベルの高さを変更することができます。
CGSize size = [descLabel.text sizeWithFont:descLabel.font constrainedToSize:CGSizeMake(labelWidth, labelHeight)];
CGRect frame = descLabel.frame;
frame.size.height = size.height;
[yourLabel setFrame:frame];
返されるサイズは、ラベルの内容に最も適しています。ラベルの高さがそのコンテンツに合わせられている場合、コンテンツがラベルの中央に配置されていても問題はありません。
投稿された他のすべてのソリューションを基にして、alignmentプロパティを設定するときに垂直方向のアライメントを処理する簡単な小さなUILabelサブクラスを作りました。これにより、向きの変更時にラベルも更新され、テキストの高さが制限され、ラベルの幅が元のサイズのままになります。
.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];
}
この問題に対する簡単な解決策
ラベルの下にUIStackView
を配置します。
次に、AutoLayoutを使用してラベルの垂直方向の間隔を0に設定し、上部をラベルの下部にあるものに固定します。ラベルは大きくならず、stackViewは大きくなります。私がこれについて好きなのは、スタックビューがレンダリングされていないということです。それで、それは本当に時間レンダリングを無駄にしていません。オートレイアウトの計算をしても。
あなたはおそらくContentHuggingとResistanceで遊ぶ必要があるでしょうが、それも同様に簡単です。
時々私はこの問題をグーグルしてここに戻ってきます。今回は私が一番簡単だと思う考えを持っていました、そしてそれが悪いパフォーマンス賢明だとは思わない。 私はAutoLayoutを使っているだけで、フレームの計算に迷惑をかけたくないと言う必要があります。それはただ…ヤックです。
Interface Builderでheight constraint
をラベルに設定し、IBOutletでコードにバインドし、その高さを変更してテキストを具体的な垂直位置に表示することで、より柔軟に行うことができます。中央揃えと下揃えの例:
labelHeightConstraint.constant = centerAlignment ? 30 : 15
layoutIfNeeded()
これが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
}