iOSアプリケーションのUILabelの左上揃えを設定するにはどうすればよいですか?


99

nibファイルにラベルを1つ追加しましたが、そのラベルの左上揃えにする必要があります。実行時にテキストを提供しているので、行数はわかりません。したがって、テキストに1行しか含まれていない場合は、垂直方向に中央揃えで表示されます。その配置は、その前にある私のそれぞれのラベルと一致していません。

例えば:

ここに画像の説明を入力してください

奇妙に見える:(

ラベルテキストを左上揃えに設定できる方法はありますか?


回答:



64

とても簡単です。プロパティをUILabel使用してサブカルスを作成し、verticalAlignmentオーバーライドtextRectForBounds:limitedToNumberOfLinesして、上部、中央、下部の垂直方向の配置の正しい境界を返します。これがコードです:

SOLabel.h

#import <UIKit/UIKit.h>

typedef enum
{
    VerticalAlignmentTop = 0, // default
    VerticalAlignmentMiddle,
    VerticalAlignmentBottom,
} VerticalAlignment;

@interface SOLabel : UILabel

   @property (nonatomic, readwrite) VerticalAlignment verticalAlignment;

@end

SOLabel.m

@implementation SOLabel

-(id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (!self) return nil;

    // set inital value via IVAR so the setter isn't called
    _verticalAlignment = VerticalAlignmentTop;

    return self;
}

-(VerticalAlignment) verticalAlignment
{
    return _verticalAlignment;
}

-(void) setVerticalAlignment:(VerticalAlignment)value
{
    _verticalAlignment = value;
    [self setNeedsDisplay];
}

// align text block according to vertical alignment settings
-(CGRect)textRectForBounds:(CGRect)bounds 
    limitedToNumberOfLines:(NSInteger)numberOfLines
{
   CGRect rect = [super textRectForBounds:bounds 
                   limitedToNumberOfLines:numberOfLines];
    CGRect result;
    switch (_verticalAlignment)
    {
       case VerticalAlignmentTop:
          result = CGRectMake(bounds.origin.x, bounds.origin.y, 
                              rect.size.width, rect.size.height);
           break;

       case VerticalAlignmentMiddle:
          result = CGRectMake(bounds.origin.x, 
                    bounds.origin.y + (bounds.size.height - rect.size.height) / 2,
                    rect.size.width, rect.size.height);
          break;

       case VerticalAlignmentBottom:
          result = CGRectMake(bounds.origin.x, 
                    bounds.origin.y + (bounds.size.height - rect.size.height),
                    rect.size.width, rect.size.height);
          break;

       default:
          result = bounds;
          break;
    }
    return result;
}

-(void)drawTextInRect:(CGRect)rect
{
    CGRect r = [self textRectForBounds:rect 
                limitedToNumberOfLines:self.numberOfLines];
    [super drawTextInRect:r];
}

@end

3
また、このソリューションを実行する前に、SOで他の多くのソリューションを試しました。それは完璧に働きました!StoryBoardでこれを行う場合は、CustomClass属性を(ユーティリティインスペクターで)UILabelではなくSOLabel(または名前を付ける名前)に設定してください。
TMc、2014年

これはとても役に立ちます、ありがとう。中央揃えまたは右揃えのテキストでは機能しませんがbounds.size.widthrect.size.widthinの代わりに使用するtextRectForBounds:limitedToNumberOfLines:と問題が解決するようです。
ジェフハックワース2015

1
iOS 9 Xcode 7で「スレッド1:EXC_BAD_ACCESS(コード2、アドレス= 0x ...)」に遭遇した場合は、単にセッターとゲッターを削除するだけです-(VerticalAlignment)verticalAlignment; 変数は@propertyであるため、-(void)setVerticalAlignment:(VerticalAlignment)value関数。合成され、アクセサが含まれています。
felixwcf 2016年

「textRectForBounds」-結果= CGRectMake(rect.origin.x、bounds.origin.y、rect.size.width、rect.size.height); 私の作品をrightAlignment UILableにするため。
g212gs 2016年

50

StoryBoardでAutoLayoutを使用するソリューションを見つけました。

1)行数を0に、テキストの配置を左に設定します。

ここに画像の説明を入力してください

2)高さの制約を設定します。

ここに画像の説明を入力してください

3)高さ制約は関係にある必要があります-より少ないか等しい

ここに画像の説明を入力してください

4)

   override func viewWillLayoutSubviews() {
        sampleLabel.sizeToFit()
    }

次のような結果が得られました。

ここに画像の説明を入力してください


2
再利用できるUITableViewCellでも、チャームのように機能します。
alex.bour

あなたは置いてくださいviewWillLayoutSubviewsコントローラまたはセルファイルに?コントローラーの場合、どのようにしてセルからUILabelにアクセスしますか?
Craig.Pearce 2016

ステップ4はどこに置きますか?新しいユーザーとして、私は純粋なUIソリューションに興奮しましたが、そのコードはどこからともなく出てきて、どこに置く
べきかわかり

SampleClass.swiftまたはSampleTableViewCell.swiftのいずれか
AG

これが解決策です。完全に動作し、ハックやサブクラス化は必要ありません。
Curious101 2018

44

SOLabelは私に適しています。

Swift 3および5:

このバージョンは元のバージョンから更新され、RTL言語をサポートできるようになりました。

public class VerticalAlignLabel: UILabel {
    enum VerticalAlignment {
        case top
        case middle
        case bottom
    }

    var verticalAlignment : VerticalAlignment = .top {
        didSet {
            setNeedsDisplay()
        }
    }

    override public func textRect(forBounds bounds: CGRect, limitedToNumberOfLines: Int) -> CGRect {
        let rect = super.textRect(forBounds: bounds, limitedToNumberOfLines: limitedToNumberOfLines)

        if UIView.userInterfaceLayoutDirection(for: .unspecified) == .rightToLeft {
            switch verticalAlignment {
            case .top:
                return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
            case .middle:
                return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height)
            case .bottom:
                return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height)
            }
        } else {
            switch verticalAlignment {
            case .top:
                return CGRect(x: bounds.origin.x, y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
            case .middle:
                return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height)
            case .bottom:
                return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height)
            }
        }
    }

    override public func drawText(in rect: CGRect) {
        let r = self.textRect(forBounds: rect, limitedToNumberOfLines: self.numberOfLines)
        super.drawText(in: r)
    }
}

スウィフト1:

class UIVerticalAlignLabel: UILabel {

enum VerticalAlignment : Int {
    case VerticalAlignmentTop = 0
    case VerticalAlignmentMiddle = 1
    case VerticalAlignmentBottom = 2
}

var verticalAlignment : VerticalAlignment = .VerticalAlignmentTop {
    didSet {
        setNeedsDisplay()
    }
}

required init(coder aDecoder: NSCoder){
    super.init(coder: aDecoder)
}

override func textRectForBounds(bounds: CGRect, limitedToNumberOfLines: Int) -> CGRect {
    let rect = super.textRectForBounds(bounds, limitedToNumberOfLines: limitedToNumberOfLines)

    switch(verticalAlignment) {
        case .VerticalAlignmentTop:
            return CGRectMake(bounds.origin.x, bounds.origin.y, rect.size.width, rect.size.height)
        case .VerticalAlignmentMiddle:
            return CGRectMake(bounds.origin.x, bounds.origin.y + (bounds.size.height - rect.size.height) / 2, rect.size.width, rect.size.height)
        case .VerticalAlignmentBottom:
            return CGRectMake(bounds.origin.x, bounds.origin.y + (bounds.size.height - rect.size.height), rect.size.width, rect.size.height)
        default:
            return bounds
    }
}

override func drawTextInRect(rect: CGRect) {
    let r = self.textRectForBounds(rect, limitedToNumberOfLines: self.numberOfLines)
    super.drawTextInRect(r)
    }
}

次のコードを使用してラベルを作成しようとすると、var myLabel = VerticalAlignLabel()「パラメーター 'coder'の引数がありません」が返されます。このVerticalAlignLabelサブクラスを使用してラベルを作成するにはどうすればよいですか?
RanLearns 2017年

1
今すぐSwiftバージョン3を試してください-必要のない必須のinitがありました。
totiG 2017年

14

私の場合、それはbottom space制約の問題でした。に設定しました= 16

に設定するとbottom to >= 16、この問題は解決しました。

また、ラベルに高さの制約がある場合は、それを削除する必要があります。

サイズインスペクタでのラベルの制約ビューは次のとおりです。

拘束


ラベルを選択しても、拘束オプションはありません。
velkoon 2018年

最も簡単な修正-制約と自動レイアウトがそれを処理します。ありがとう!
ジェイソン

13

あなたのコードで

label.text = @"some text";
[label sizeToFit];

テーブルセルまたは別のデータで再利用される他のビューでそれを使用する場合は、sizeToFitを呼び出す前に、元のフレームをどこかに保存してリセットする必要があることに注意してください。


この時点では、実際にはすべてAutolayoutに任せることをお勧めします。これはもう必要ありません。
n13 2015年

9

同じ問題の別の解決策を見つけました。UITextView代わりに使用し、機能をにUILabel切り替えeditable()ましたfalse


@geekyaleksなぜこれは馬鹿なハックなのか?まともな回避策のようですが、質問に対する直接の回答ではないこと以外に、他の問題はありますか?
クリストファーラーセン2017年

ジョブに適切なUIコンポーネントを使用していないため、これは適切ではありません。垂直方向の配置という単純なものに対する妥協であってはなりません。ジョブに適切なコンポーネントを使用する必要があります。それ以外はハックです...
geekyaleks 2017年

7

私もこの問題を抱えていましたが、UILabelのプロパティとメソッドを設定する順序が重要であることがわかりました。

[label sizeToFit]前に呼び出した場合label.font = [UIFont fontWithName:@"Helvetica" size:14];、テキストは上に揃えられませんが、入れ替えると、揃えられます。

また、テキストを最初に設定すると違いが出ることにも気づきました。

お役に立てれば。


すごい。最後にsizeToFit()を呼び出す必要があります。
MKatleast3 2015年

4

インターフェイスビルダーを使用しているときに、ラベルの制約を設定します(高さと幅も必ず設定してください)。次に、サイズインスペクターでラベルの高さを確認します。そこで、=の代わりに> =を読み取ってもらいます。次に、そのビューコントローラーの実装で、行数を0に設定し(IBでも実行できます)、ラベル[label sizeToFit]を設定します。テキストが長くなると、ラベルの高さが増し、テキストが左上に配置されます。


4

デフォルトで左上隅から始まる編集不可能なテキストが必要な場合は、ラベルの代わりにテキストビューを使用して、次のように状態を編集不可に設定できます。

textview.isEditable = false

ラベルをいじるよりもはるかに簡単...

乾杯!


3

SoLabelを使用したソリューションが機能します。ありがとうございます。

怒鳴る私はモノタッチ版を追加しました:

    public class UICustomLabel : UILabel
{
    private UITextVerticalAlignment _textVerticalAlignment;

    public UICustomLabel()
    {
        TextVerticalAlignment = UITextVerticalAlignment.Top;
    }

    public UITextVerticalAlignment TextVerticalAlignment
    {
        get
        {
            return _textVerticalAlignment;
        }
        set
        {
            _textVerticalAlignment = value;
            SetNeedsDisplay();
        }
    }

    public override void DrawText(RectangleF rect)
    {
        var bound = TextRectForBounds(rect, Lines);
        base.DrawText(bound);
    }

    public override RectangleF TextRectForBounds(RectangleF bounds, int numberOfLines)
    {
        var rect = base.TextRectForBounds(bounds, numberOfLines);
        RectangleF resultRect;
        switch (TextVerticalAlignment)
        {
            case UITextVerticalAlignment.Top:
                resultRect = new RectangleF(bounds.X, bounds.Y, rect.Size.Width, rect.Size.Height);
                break;
            case UITextVerticalAlignment.Middle:
                resultRect = new RectangleF(bounds.X,
                                            bounds.Y + (bounds.Size.Height - rect.Size.Height)/2,
                                            rect.Size.Width, rect.Size.Height);
                break;
            case UITextVerticalAlignment.Bottom:
                resultRect = new RectangleF(bounds.X,
                                            bounds.Y + (bounds.Size.Height - rect.Size.Height),
                                            rect.Size.Width, rect.Size.Height);
                break;

            default:
                resultRect = bounds;
                break;
        }

        return resultRect;
    }
}

public enum UITextVerticalAlignment
{
    Top = 0, // default
    Middle,
    Bottom
}


2

totiGの素晴らしい答えの上に構築し、StoryBoardからUILabelの垂直方向の配置を非常に簡単にカスタマイズできるIBDesignableクラスを作成しました。StoryBoard IDインスペクターからUILabelのクラスを「VerticalAlignLabel」に設定していることを確認してください。垂直方向の配置が有効にならない場合は、エディター->すべてのビューを更新に移動してください。

仕組み:UILabelのクラスを正しく設定すると、ストーリーボードに整数(配置コード)を受け取る入力フィールドが表示されます。

更新:中央揃えのラベルのサポートを追加しました〜Sev


上揃えに0を入力します

中央揃えに1を入力します

下揃えに2を入力します

    @IBDesignable class VerticalAlignLabel: UILabel {
    
    @IBInspectable var alignmentCode: Int = 0 {
        didSet {
            applyAlignmentCode()
        }
    }
    
    func applyAlignmentCode() {
        switch alignmentCode {
        case 0:
            verticalAlignment = .top
        case 1:
            verticalAlignment = .topcenter
        case 2:
            verticalAlignment = .middle
        case 3:
            verticalAlignment = .bottom
        default:
            break
        }
    }
    
    override func awakeFromNib() {
        super.awakeFromNib()
        self.applyAlignmentCode()
    }
    
    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        
        self.applyAlignmentCode()
    }
    
    enum VerticalAlignment {
        case top
        case topcenter
        case middle
        case bottom
    }
    
    var verticalAlignment : VerticalAlignment = .top {
        didSet {
            setNeedsDisplay()
        }
    }
    
    override public func textRect(forBounds bounds: CGRect, limitedToNumberOfLines: Int) -> CGRect {
        let rect = super.textRect(forBounds: bounds, limitedToNumberOfLines: limitedToNumberOfLines)
        
        if #available(iOS 9.0, *) {
            if UIView.userInterfaceLayoutDirection(for: .unspecified) == .rightToLeft {
                switch verticalAlignment {
                case .top:
                    return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
                case .topcenter:
                    return CGRect(x: self.bounds.size.width - (rect.size.width / 2), y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
                case .middle:
                    return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height)
                case .bottom:
                    return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height)
                }
            } else {
                switch verticalAlignment {
                case .top:
                    return CGRect(x: bounds.origin.x, y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
                case .topcenter:
                    return CGRect(x: (self.bounds.size.width / 2 ) - (rect.size.width / 2), y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
                case .middle:
                    return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height)
                case .bottom:
                    return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height)
                }
            }
        } else {
            // Fallback on earlier versions
            return rect
        }
    }
    
    override public func drawText(in rect: CGRect) {
        let r = self.textRect(forBounds: rect, limitedToNumberOfLines: self.numberOfLines)
        super.drawText(in: r)
    }
}


2

UILabelをUITextViewに変更することもできます。UITextViewの利点は、テキストが左上に自動的に配置されることを除いて、基本的に同じことを行うためです。


1

私はこの問題を抱えていますが、私のラベルはUITableViewCellにあり、問題を解決する最も簡単な方法は空のUIViewを作成し、その上にラベルを設定し、呪いをかけずに上部と左側のみに制約を設定することでした行数を0に設定します


0

iOS 7の場合、それが私が作成し、私のために働いたものです

@implementation UILabel (VerticalAlign)
- (void)alignTop
{
    CGSize boundingRectSize = CGSizeMake(self.frame.size.width, CGFLOAT_MAX);
    NSDictionary *attributes = @{NSFontAttributeName : self.font};
    CGRect labelSize = [self.text boundingRectWithSize:boundingRectSize options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
                                              attributes:attributes
                                                 context:nil];
    int numberOfLines= ceil(labelSize.size.height / self.font.lineHeight);

    CGRect newFrame = self.frame;
    newFrame.size.height = numberOfLines * self.font.lineHeight;
    self.frame = newFrame;
}

- (void)alignBottom
{
    CGSize boundingRectSize = CGSizeMake(self.frame.size.width, CGFLOAT_MAX);
    NSDictionary *attributes = @{NSFontAttributeName : self.font};
    CGRect labelSize = [self.text boundingRectWithSize:boundingRectSize options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
                                            attributes:attributes
                                               context:nil];
    int numberOfLines= ceil(labelSize.size.height / self.font.lineHeight);

    int numberOfNewLined = (self.frame.size.height/self.font.lineHeight) - numberOfLines;

    NSMutableString *newLines = [NSMutableString string];
    for(int i=0; i< numberOfNewLined; i++){
        [newLines appendString:@"\n"];
    }
    [newLines appendString:self.text];
    self.text = [newLines mutableCopy];
}

0

Swift 2.0::UILabel拡張機能の使用

空の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)

何が必要sampleLabel: UILabel?か説明していただけますか?
Craig.Pearce

このfunc makeLabelTextPosition(sampleLabel:UILabel ?, positionIdentifier:String){}では、UILabelオブジェクトを渡す必要があります。
AG

0

@totiGの回答のSwift 3バージョン

class UIVerticalAlignLabel: UILabel {
    enum VerticalAlignment : Int {
        case VerticalAlignmentTop = 0
        case VerticalAlignmentMiddle = 1
        case VerticalAlignmentBottom = 2
    }

    @IBInspectable var verticalAlignment : VerticalAlignment = .VerticalAlignmentTop {
        didSet {
            setNeedsDisplay()
        }
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override func textRect(forBounds bounds: CGRect, limitedToNumberOfLines: Int) -> CGRect {
        let rect = super.textRect(forBounds: bounds, limitedToNumberOfLines: limitedToNumberOfLines)

        switch(verticalAlignment) {
        case .VerticalAlignmentTop:
            return CGRect(x: bounds.origin.x, y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
        case .VerticalAlignmentMiddle:
            return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height)
        case .VerticalAlignmentBottom:
            return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height)
        }
    }

    override func drawText(in rect: CGRect) {
        let r = self.textRect(forBounds: rect, limitedToNumberOfLines: self.numberOfLines)
        super.drawText(in: r)
    }
}

0

@totiGの答えは正しく、私の問題を解決しました。しかし、この方法を実装しているときに問題が見つかりました。5sやSEなどの小型のデバイスでは、これはうまくいきません。私は設定する必要がlabel.sizeToFit()override func layoutSubViews()

override func layoutSubViews() {
    super.layoutSubViews()
    // Do other works if needed
    label.sizeToFit()
}

0

スウィフト5

それはシンプルで、プロパティの順序がすべてです。

titleLabel.frame = CGRect(x: 20, y: 20, width: 374, height: 291.2)
titleLabel.backgroundColor = UIColor.clear //set a light color to see the frame
titleLabel.textAlignment = .left
titleLabel.lineBreakMode = .byTruncatingTail
titleLabel.numberOfLines = 4
titleLabel.font = UIFont(name: "HelveticaNeue-Bold", size: 35)
titleLabel.text = "Example"
titleLabel.sizeToFit()
self.view.addSubview(titleLabel)

-2

iOSアプリケーションのUILabelの左上揃えを設定するにはどうすればよいですか?ラベルコンテンツモードを「左上」に設定するとうまくいきます。ありがとうございました。
iOSアプリケーションのUILabelの左上揃えを設定するにはどうすればよいですか? ラベル設定コンテンツモードを「左上」に設定してください。ありがとうございます


1
私には何もしません。これは、直感的にはそれが解決策である必要があるように思われます。そのため、うまくいかなかった(または、一見するとすべてをうまくやっている)ときにGoogleに目を向けました。
velkoon 2018年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.