UILabelにスペース/パディングを追加する


187

私が持っているUILabel私がトップで、下にスペースを追加する場所。制約の高さを最小にして、次のように変更しました。

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

編集:これを行うために私は使用しました:

  override func drawTextInRect(rect: CGRect) {
        var insets: UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 10.0, bottom: 0.0, right: 10.0)
        super.drawTextInRect(UIEdgeInsetsInsetRect(rect, insets))

    } 

しかし、3行以上書いても問題は同じなので、別の方法を見つける必要があります。

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



最終的に、すべての動的なケースで、再レイアウトやその他の問題を必要としない、UILabelの完全なドロップイン代替として、これを適切に行う方法を正確に理解しました。ふHE。 stackoverflow.com/a/58876988/294884
Fattie

回答:


122

UILabelをサブクラス化せずに使い続けたい場合、Mundiは明確な解決策を提供します。

あるいは、UILabelをUIViewでラップするのを避けたい場合は、UITextViewを使用してUIEdgeInsets(パディング)またはサブクラスUILabelの使用を有効にして、UIEdgeInsetsをサポートできます。

UITextViewを使用すると、インセット(OBJ-C)を提供するだけで済みます。

textView.textContainerInset = UIEdgeInsetsMake(10, 0, 10, 0);

または、UILabelをサブクラスする場合、このアプローチの例は、drawTextInRectメソッド
(OBJ-C)をオーバーライドすることです。

- (void)drawTextInRect:(CGRect)uiLabelRect {
    UIEdgeInsets myLabelInsets = {10, 0, 10, 0};
    [super drawTextInRect:UIEdgeInsetsInsetRect(uiLabelRect, myLabelInsets)];
}

さらに、TOP、LEFT、BOTTOM、RIGHTのインセット変数を使用して、新しいサブクラス化されたUILabelを提供できます。

コードの例は次のとおりです。

.h(OBJ-C)

float topInset, leftInset,bottomInset, rightInset;

.m(OBJ-C)

- (void)drawTextInRect:(CGRect)uiLabelRect {
    [super drawTextInRect:UIEdgeInsetsInsetRect(uiLabelRect, UIEdgeInsetsMake(topInset,leftInset,bottomInset,rightInset))];
}

編集#1:

私が見たことから、それをサブクラス化するとき、UILabelの組み込みコンテンツサイズをオーバーライドする必要があるようです。

したがって、次のように組み込みコンテンツサイズをオーバーライドする必要があります。

- (CGSize) intrinsicContentSize {
    CGSize intrinsicSuperViewContentSize = [super intrinsicContentSize] ;
    intrinsicSuperViewContentSize.height += topInset + bottomInset ;
    intrinsicSuperViewContentSize.width += leftInset + rightInset ;
    return intrinsicSuperViewContentSize ;
}

また、個別に編集するのではなく、次のメソッドを追加してインセットを編集します。

- (void) setContentEdgeInsets:(UIEdgeInsets)edgeInsets {
    topInset = edgeInsets.top;
    leftInset = edgeInsets.left;
    rightInset = edgeInsets.right; 
    bottomInset = edgeInsets.bottom;
    [self invalidateIntrinsicContentSize] ;
}

UILabelのサイズを更新してエッジインセットと一致させ、参照した複数行の必要性をカバーします。

#2を編集

少し検索したところ、このGistがIPInsetLabelで見つかりました。これらのソリューションがどれも機能しない場合は、試してみることができます。

#3を編集

この問題について同様の質問(重複)がありました。
利用可能なソリューションの完全なリストについては、この回答を参照してください:UILabelテキストマージン


すみませんが、私はすでに使用しました: `オーバーライドfunc drawTextInRect(rect:CGRect){var insets:UIEdgeInsets = UIEdgeInsets(top:0.0、left:10.0、bottom:0.0、right:10.0)super.drawTextInRect(UIEdgeInsetsInsetRect(rect、insets ))} `それは仕事をしない結果が同じであるため、動的に動作しません...
Annachiara

UILabelの代わりにUITextViewを試しましたか?または本当にUILabelを使用する必要がありますか?
nunofmendes 2014

@Annachiara私が行った編集を確認してください。機能するかどうかを確認します。
nunofmendes 2014

OK。テキストビューは機能しましたか?Swiftで書いていないのは残念ですが、私はまだObj-Cモードです。そのコードの私の目標は、あなたがいくつかの結論に達するのを助けることでした。それができたことを願っています。
nunofmendes 2014

1
TextViewといくつかのストーリーボード設定およびself.textview.textContainerInset = UIEdgeInsetsMake(0、10、10、10);を使用します。ようやく動く!よろしくお願いします!
アナキアラ

208

私はSwift 4.2で試してみましたが、うまくいけばうまくいきます!

@IBDesignable class PaddingLabel: UILabel {

    @IBInspectable var topInset: CGFloat = 5.0
    @IBInspectable var bottomInset: CGFloat = 5.0
    @IBInspectable var leftInset: CGFloat = 7.0
    @IBInspectable var rightInset: CGFloat = 7.0

    override func drawText(in rect: CGRect) {
        let insets = UIEdgeInsets(top: topInset, left: leftInset, bottom: bottomInset, right: rightInset)
        super.drawText(in: rect.inset(by: insets))
    }

    override var intrinsicContentSize: CGSize {
        let size = super.intrinsicContentSize
        return CGSize(width: size.width + leftInset + rightInset,
                      height: size.height + topInset + bottomInset)
    }   

    override var bounds: CGRect {
        didSet {
            // ensures this works within stack views if multi-line
            preferredMaxLayoutWidth = bounds.width - (leftInset + rightInset)
        }
    } 
}

または、ここでCocoaPodsを使用できますhttps://github.com/levantAJ/PaddingLabel

pod 'PaddingLabel', '1.2'

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


6
Uilabelの幅は変化せず、テキストは「...」になります
neobie '12年

1
@Tai Le、共有してくれてありがとう、私はそれをtableviewで使用しました。なぜテキストをトリミングするのかわかりません。学生は学生になる
vishwa.deepak

1
@ティム多分あなたが使用するmin
つもりだった

4
ここで警告の言葉。私はこのソリューションをUILabelサブクラスで使用しています。これらのラベルをマルチラインモードで使用する場合、縦型のUIStackViewには問題があります。時々、ラベルはラベルのサイズを正しく設定せずにテキストをラップしているように見えることがあります。そのため、1つまたは2つの単語が文字列の最後から欠落してしまいます。現在、解決策はありません。作ったらここに書きます。ここにあることを証明する前に、私はこの問題に何時間も突っ込んだ。
Darren Black

1
このような状況で機能させるには、「setBounds」をオーバーライドし、self.preferredMaxLayoutWidthを境界の幅から左右のインセットを差し引いた値に設定する必要があります
Arnaud Barisain-Monrose

82

スウィフト3

import UIKit

class PaddingLabel: UILabel {

   @IBInspectable var topInset: CGFloat = 5.0
   @IBInspectable var bottomInset: CGFloat = 5.0
   @IBInspectable var leftInset: CGFloat = 5.0
   @IBInspectable var rightInset: CGFloat = 5.0

   override func drawText(in rect: CGRect) {
      let insets = UIEdgeInsets(top: topInset, left: leftInset, bottom: bottomInset, right: rightInset)
      super.drawText(in: UIEdgeInsetsInsetRect(rect, insets))
   }

   override var intrinsicContentSize: CGSize {
      get {
         var contentSize = super.intrinsicContentSize
         contentSize.height += topInset + bottomInset
         contentSize.width += leftInset + rightInset
         return contentSize
      }
   }
}

ほんの少しのコメント:アイデンティティインスペクター(カスタムクラス)でこのクラスをラベル付けし、ラベルパディングという名前の属性インスペクターで新しい属性を使用します。また、以下の5パディングはeffectlessある
イマンkazemayni

3
ラベルがその高さを計算するとき、それはゼロのパディングを仮定するので、これは常に複数行のラベルで正しく機能しません。
fhucho

76

あなたはIBからそれを正しく行うことができます:

  1. テキストを属性付きに変更する

属性付きテキスト

  1. 「...」でドロップダウンリストに移動

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

  1. 行、段落、テキストのパディングプロパティがいくつか変更され、最初の行がインデントされます。

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

  1. 結果を確認する

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


1
ストーリーボードではテキストの変化を確認できますが、アプリを実行すると、テキストに変更が表示されません... T_T ..ラベルがカスタムセル内にありますが、問題はありますか?
A. Trejo 2016

1
@ A.Trejo実行時にラベルプロパティを設定するカスタムセルである可能性があります。
Pierre-Yves Guillemet 2016

1
変更はストーリーボードに表示されますが、アプリを実行しても変更はありません。
レンツ2017年

4
これは、プログラムでテキストを設定する場合には適用されません。
Nij 2018

1
これは答えではありません。制御できるのは最初の行のインデントのみで、ボットはすべての方向のパディングではありません。
rommex

49

SWIFT 4

プロジェクト内のすべてのUILabel子で使用可能な使いやすいソリューション。

例:

let label = UILabel()
    label.<Do something>
    label.padding = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 0)

UILabel拡張

import UIKit

extension UILabel {
    private struct AssociatedKeys {
        static var padding = UIEdgeInsets()
    }

    public var padding: UIEdgeInsets? {
        get {
            return objc_getAssociatedObject(self, &AssociatedKeys.padding) as? UIEdgeInsets
        }
        set {
            if let newValue = newValue {
                objc_setAssociatedObject(self, &AssociatedKeys.padding, newValue as UIEdgeInsets?, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            }
        }
    }

    override open func draw(_ rect: CGRect) {
        if let insets = padding {
            self.drawText(in: rect.inset(by: insets))
        } else {
            self.drawText(in: rect)
        }
    }

    override open var intrinsicContentSize: CGSize {
        guard let text = self.text else { return super.intrinsicContentSize }

        var contentSize = super.intrinsicContentSize
        var textWidth: CGFloat = frame.size.width
        var insetsHeight: CGFloat = 0.0
        var insetsWidth: CGFloat = 0.0

        if let insets = padding {
            insetsWidth += insets.left + insets.right
            insetsHeight += insets.top + insets.bottom
            textWidth -= insetsWidth
        }

        let newSize = text.boundingRect(with: CGSize(width: textWidth, height: CGFloat.greatestFiniteMagnitude),
                                        options: NSStringDrawingOptions.usesLineFragmentOrigin,
                                        attributes: [NSAttributedString.Key.font: self.font], context: nil)

        contentSize.height = ceil(newSize.size.height) + insetsHeight
        contentSize.width = ceil(newSize.size.width) + insetsWidth

        return contentSize
    }
}

1
答えを簡単に説明してください。コードを投稿するだけではありません。
lmiguelvargasf 2017年

4
拡張機能により、numberOfLinesの0の値がキャンセルされます
Antoine Bodart 2017

これはすばらしいことですが、複数の行で問題が発生しています。2行目を追加したり、0行のままにしたりしても、常に1行表示されます。あなたはそれを解決する方法を知っていますか?
Mago Nicolas Palacios 2017年

1
@AntoineBodartは、numberOfLinesの問題をなんとか解決しましたか?
Mago Nicolas Palacios 2017年

@ AntoineBodart、@ Mago Nicolas Palacios-解決しました!
iEvgen Podkorytov 2017年

47

UIViewスーパービューとしてaを使用し、自動レイアウトでラベルに固定マージンを定義します。


1
drawTextInRect 1行のみでintrinsicContentSize機能し、水平パディングでは機能しません。UIView内にUILabelをラップするのが良い方法です
onmyway133

8
IBを使用している場合は、メニューエディター->埋め込み->表示を覚えてください。最初にUILabelを選択するだけです:)
Graham Perks

46

既に組み込まれているUIButtonを使用するだけです。すべての追加のボタン機能をオフにすると、エッジアセットを設定できるラベルが作成されます。

let button = UIButton()
button.contentEdgeInsets = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
button.setTitle("title", for: .normal)
button.tintColor = .white // this will be the textColor
button.isUserInteractionEnabled = false

2
ちょっとこれは素晴らしいヒントです!拡張は必要ありません!:-D
フェリペフェリ

2
isUserInteractionEnabled = false無効にするには設定が便利です。
mxcl 2017

すばらしいヒントです...私は、拡張を行うよりも、これを行いたいと思います。
ロス

1
インターフェイスビルダーでも実行できるという大きな利点があるすばらしいヒント
Ely

1
サブクラス化などなしの最良のソリューション
MeGaPk

16

ストーリーボードなし:

class PaddingLabel: UILabel {

    var topInset: CGFloat
    var bottomInset: CGFloat
    var leftInset: CGFloat
    var rightInset: CGFloat

    required init(withInsets top: CGFloat, _ bottom: CGFloat,_ left: CGFloat,_ right: CGFloat) {
        self.topInset = top
        self.bottomInset = bottom
        self.leftInset = left
        self.rightInset = right
        super.init(frame: CGRect.zero)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func drawText(in rect: CGRect) {
        let insets = UIEdgeInsets(top: topInset, left: leftInset, bottom: bottomInset, right: rightInset)
        super.drawText(in: UIEdgeInsetsInsetRect(rect, insets))
    }

    override var intrinsicContentSize: CGSize {
        get {
            var contentSize = super.intrinsicContentSize
            contentSize.height += topInset + bottomInset
            contentSize.width += leftInset + rightInset
            return contentSize
        }
    }
}

使用法:

let label = PaddingLabel(8, 8, 16, 16)
label.font = .boldSystemFont(ofSize: 16)
label.text = "Hello World"
label.backgroundColor = .black
label.textColor = .white
label.textAlignment = .center
label.layer.cornerRadius = 8
label.clipsToBounds = true
label.sizeToFit()

view.addSubview(label)

結果:


動作しますが、複数の行を受け入れる方法を知っていますか?"PaddingLabel(withInsets:8、8、16、16)"でinitを変更するだけ
CamiloOrtegón2017

16

UILabel完全なソリューションのパディング。2020年に更新されました。

やらなければならないことが3つあることがわかりました。

1. textRect#forBounds を新しい小さいサイズで呼び出す必要があります

2. drawTextを新しい小さいサイズでオーバーライドする必要があります

3.動的にサイズ変更されたセルの場合、intrinsicContentSizeを調整する必要があります

以下の典型的な例では、テキストユニットはテーブルビュー、スタックビュー、または同様の構造になっており、固定幅になります。この例では、60、20、20、24のパディングが必要です。

したがって、「既存の」intrinsicContentSizeを受け取り、実際に高さに80を追加します。

繰り返す ...

エンジンによって「これまでに」計算された高さを文字通り「取得」し、その値を変更する必要があります。

そのプロセスは混乱しますが、それはそれがどのように機能するかです。私にとって、Appleは「予備の高さ計算」のような名前の呼び出しを公開する必要があります。

次に、textRect#forBounds呼び出しを新しい小さいサイズで実際に使用する必要があります

したがって、textRect#forBoundsでは、最初にサイズを小さくしてから super 呼び出します。

警告!前ではなく、にスーパー呼び出す必要あります!

このページのすべての試行とディスカッションを注意深く調査すると、それが正確な問題です。一部のソリューションは「ほとんど機能しているようです」が、特定の状況では機能しないと誰かが報告することに注意してください。これは確かに正確な理由です。紛らわしいことに、前ではなく「後でスーパーに呼び出す」必要があります。

したがって、「間違った順序」でsuperを呼び出すと、通常は機能しますが、特定のテキスト長では機能しません

これは、「スーパーファーストを誤って行う」正確な視覚的な例です。

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

60、20、20、24のマージンは正しいが、サイズの計算は実際には間違っていることに注意してください。これは、textRect#forBoundsの「スーパーファースト」パターンで行われたためです。

修繕:

textRect#forBoundsエンジンが計算を正しく行う方法を知っているのは今のところです

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

最後に!

この例でも、UILabelは、幅が固定されている一般的な状況で使用されています。したがって、intrinsicContentSizeでは、必要な全体的な高さを「追加」する必要があります。(幅に「追加」する必要はありません。固定されているため、意味がありません。)

そして、textRect番号のforBoundsにあなたは境界を取得する自動レイアウトによって、あなたは「これまでの提案」引くあなたの利益を、とだけにしてあなたに結果を与えるであろう、スーパーで言うことですtextRect#forBoundsエンジン、再び呼び出します。

最後に、単純にdrawTextで、同じ小さなボックスに描画します。

ふew!

let UIEI = UIEdgeInsets(top: 60, left: 20, bottom: 20, right: 24) // as desired

override var intrinsicContentSize:CGSize {
    numberOfLines = 0       // don't forget!
    var s = super.intrinsicContentSize
    s.height = s.height + UIEI.top + UIEI.bottom
    s.width = s.width + UIEI.left + UIEI.right
    return s
}

override func drawText(in rect:CGRect) {
    let r = rect.inset(by: UIEI)
    super.drawText(in: r)
}

override func textRect(forBounds bounds:CGRect,
                           limitedToNumberOfLines n:Int) -> CGRect {
    let b = bounds
    let tr = b.inset(by: UIEI)
    let ctr = super.textRect(forBounds: tr, limitedToNumberOfLines: 0)
    // that line of code MUST be LAST in this function, NOT first
    return ctr
}

もう一度。これと「ほぼ」正しい他のQAの回答は、上記の最初の画像の問題に苦しむことに注意してください- 「スーパーは間違った場所にあります」。あなたはintrinsicContentSizeでサイズをより大きくする必要があり、次にtextRect#forBoundsで最初に最初の提案の境界縮小してからsuper 呼び出す必要あります。

概要:textRect#forBoundsで「スーパーラストを呼び出す」必要があります

それが秘密です。

invalidate、sizeThatFits、needsLayout、またはその他の強制呼び出しを呼び出す必要はなく、また呼び出す必要もないことに注意してください。正しいソリューションは、通常の自動レイアウト描画サイクルで適切に機能するはずです。


ヒント:

等幅フォントを使用している場合は、次のヒントを参考にしてください。https//stackoverflow.com/a/59813420/294884


11

スウィフト4+

class EdgeInsetLabel: UILabel {
    var textInsets = UIEdgeInsets.zero {
        didSet { invalidateIntrinsicContentSize() }
    }

    override func textRect(forBounds bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect {
        let textRect = super.textRect(forBounds: bounds, limitedToNumberOfLines: numberOfLines)
        let invertedInsets = UIEdgeInsets(top: -textInsets.top,
                                          left: -textInsets.left,
                                          bottom: -textInsets.bottom,
                                          right: -textInsets.right)
        return textRect.inset(by: invertedInsets)
    }

    override func drawText(in rect: CGRect) {
        super.drawText(in: rect.inset(by: textInsets))
    } 
}

使用法:

let label = EdgeInsetLabel()
label.textInsets = UIEdgeInsets(top: 2, left: 6, bottom: 2, right: 6)

WAIT-場合によっては、これで実際に問題が発生しました。以前は、これが最も正解でした。以下に正解を掲載しました。
Fattie

問題を示す画像を私の回答に含めました
Fattie、

9

Swift 3コードと実装例

class UIMarginLabel: UILabel {

    var topInset:       CGFloat = 0
    var rightInset:     CGFloat = 0
    var bottomInset:    CGFloat = 0
    var leftInset:      CGFloat = 0

    override func drawText(in rect: CGRect) {
        let insets: UIEdgeInsets = UIEdgeInsets(top: self.topInset, left: self.leftInset, bottom: self.bottomInset, right: self.rightInset)
        self.setNeedsLayout()
        return super.drawText(in: UIEdgeInsetsInsetRect(rect, insets))
    }
}

class LabelVC: UIViewController {

    //Outlets
    @IBOutlet weak var labelWithMargin: UIMarginLabel!

    override func viewDidLoad() {
        super.viewDidLoad()

        //Label settings.
        labelWithMargin.leftInset = 10
        view.layoutIfNeeded()
    }
}

ストーリーボードラベルオブジェクトにクラス名UIMarginLabelを追加することを忘れないでください。ハッピーコーディング!


8

どおりスイフト4.2(Xcodeの10ベータ6) "UIEdgeInsetsInsetRectは"非推奨されています。また、クラスをより便利にするためにクラスをpublicと宣言しました。

public class UIPaddedLabel: UILabel {

    @IBInspectable var topInset: CGFloat = 5.0
    @IBInspectable var bottomInset: CGFloat = 5.0
    @IBInspectable var leftInset: CGFloat = 7.0
    @IBInspectable var rightInset: CGFloat = 7.0

    public override func drawText(in rect: CGRect) {
        let insets = UIEdgeInsets.init(top: topInset, left: leftInset, bottom: bottomInset, right: rightInset)
        super.drawText(in: rect.inset(by: insets))
    }

    public override var intrinsicContentSize: CGSize {
        let size = super.intrinsicContentSize
        return CGSize(width: size.width + leftInset + rightInset,
                      height: size.height + topInset + bottomInset)
    }

    public override func sizeToFit() {
        super.sizeThatFits(intrinsicContentSize)
    }
}

それはうまくいきます。しかし、私はそれをCollectionViewCell内で使用しようとしましたが、再利用後(sizeToFitおよびlayoutIfNeededの後のイベント)のサイズが適切に変更されません。それをサイズ変更する方法はありますか?
ボギー

1
再利用可能なビューで動作するようにsizeToFit()を更新しました
Bogy

sizeToFit()次のように公開する必要があります:「オーバーライドするインスタンスメソッドは、その囲んでいる型と同じようにアクセス可能でなければなりません」
psyFi

7

認められた回答を少し編集しました。増加するleftInsetと問題が発生しrightInsetます。テキストの一部が消え、b / cラベルの幅が狭くなりますが、図のように高さが増加しません。

固有のコンテンツサイズが間違っているパディングラベル

この問題を解決するには、次のようにテキストの高さを再計算する必要があります。

@IBDesignable class PaddingLabel: UILabel {

  @IBInspectable var topInset: CGFloat = 20.0
  @IBInspectable var bottomInset: CGFloat = 20.0
  @IBInspectable var leftInset: CGFloat = 20.0
  @IBInspectable var rightInset: CGFloat = 20.0

  override func drawTextInRect(rect: CGRect) {
    let insets = UIEdgeInsets(top: topInset, left: leftInset, bottom: bottomInset, right: rightInset)
    super.drawTextInRect(UIEdgeInsetsInsetRect(rect, insets))
  }

  override func intrinsicContentSize() -> CGSize {
    var intrinsicSuperViewContentSize = super.intrinsicContentSize()

    let textWidth = frame.size.width - (self.leftInset + self.rightInset)
    let newSize = self.text!.boundingRectWithSize(CGSizeMake(textWidth, CGFloat.max), options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [NSFontAttributeName: self.font], context: nil)
    intrinsicSuperViewContentSize.height = ceil(newSize.size.height) + self.topInset + self.bottomInset

    return intrinsicSuperViewContentSize
  }
}

そして結果:

固有のコンテンツサイズが適切なパディングラベル

私と同じ状況にいる人々を助けたいと思います。


2
Swift 3.0を使用する場合は、新しいApple言語が以前のfuncの定義を完全に壊すため、関数名を変更する必要があります。なので、override func drawTextInRect(rect: CGRect)となりoverride func drawText(in rect: CGRect)、 エンジョイにoverride func intrinsicContentSize() -> CGSizeなりoverride var intrinsicContentSize : CGSizeます!
DoKは2016

残念ながら、私はそれを機能させませんでした。コードスイフト5で試しました override var intrinsicContentSize: CGSize { // .. return intrinsicSuperViewContentSize }
Nazmul Hasan

7

自動レイアウトを使用するだけです:

let paddedWidth = myLabel.intrinsicContentSize.width + 2 * padding
myLabel.widthAnchor.constraint(equalToConstant: paddedWidth).isActive = true

できました。


高さでも同じことができます。
ShadeToD

ありがとう、ありがとう。
Mike Taverne

7

サブクラス化を行わない別のオプションは次のとおりです。

  1. ラベルを設定 text
  2. sizeToFit()
  3. 次に、ラベルの高さを少し増やしてパディングをシミュレートします

    label.text = "someText"
    label.textAlignment = .center    
    label.sizeToFit()  
    label.frame = CGRect( x: label.frame.x, y: label.frame.y,width:  label.frame.width + 20,height: label.frame.height + 8)

驚いたことに、これは私が必要とするすべてでした、これを少し変更しました:label.frame = CGRect( x: label.frame.origin.x - 10, y: label.frame.origin.y - 4, width: label.frame.width + 20,height: label.frame.height + 8)集中化のための-10と-4
Mofe Ejegi

6

Swift 3、iOS10ソリューション:

open class UIInsetLabel: UILabel {

    open var insets : UIEdgeInsets = UIEdgeInsets() {
        didSet {
            super.invalidateIntrinsicContentSize()
        }
    }

    open override var intrinsicContentSize: CGSize {
        var size = super.intrinsicContentSize
        size.width += insets.left + insets.right
        size.height += insets.top + insets.bottom
        return size
    }

    override open func drawText(in rect: CGRect) {
        return super.drawText(in: UIEdgeInsetsInsetRect(rect, insets))
    }
}

6

Swift 3で

最良かつ簡単な方法

class UILabelPadded: UILabel {
     override func drawText(in rect: CGRect) {
     let insets = UIEdgeInsets.init(top: 0, left: 5, bottom: 0, right: 5)
     super.drawText(in: UIEdgeInsetsInsetRect(rect, insets))
    }

}

4

UILabelをサブクラス化します。(File-New-File- CocoaTouchClass-make UILabelのサブクラス)。

//  sampleLabel.swift

import UIKit

class sampleLabel: UILabel {

 let topInset = CGFloat(5.0), bottomInset = CGFloat(5.0), leftInset = CGFloat(8.0), rightInset = CGFloat(8.0)

 override func drawTextInRect(rect: CGRect) {

  let insets: UIEdgeInsets = UIEdgeInsets(top: topInset, left: leftInset, bottom: bottomInset, right: rightInset)
  super.drawTextInRect(UIEdgeInsetsInsetRect(rect, insets))

 }
 override func intrinsicContentSize() -> CGSize {
  var intrinsicSuperViewContentSize = super.intrinsicContentSize()
  intrinsicSuperViewContentSize.height += topInset + bottomInset
  intrinsicSuperViewContentSize.width += leftInset + rightInset
  return intrinsicSuperViewContentSize
 }
}

ViewControllerで:

override func viewDidLoad() {
  super.viewDidLoad()

  let labelName = sampleLabel(frame: CGRectMake(0, 100, 300, 25))
  labelName.text = "Sample Label"
  labelName.backgroundColor =  UIColor.grayColor()

  labelName.textColor = UIColor.redColor()
  labelName.shadowColor = UIColor.blackColor()
  labelName.font = UIFont(name: "HelveticaNeue", size: CGFloat(22))
  self.view.addSubview(labelName)
 }

またはストーリーボードのカスタムUILabelクラスをラベルのクラスとして関連付けます。


これらのハードコードされた値をクラスプロパティに変更した場合、私は賛成票を投じます。私はすでにこのコードを使用しています。
Juan Boero 16

@ Juan:drawTextInRectはUILabelのデフォルトのクラスプロパティであり、コードを使用してオーバーライドすることはできません。UILabelをサブクラス化し、必要なフレーム変更を追加するためのベストプラクティス。とにかく、継承機能としては便利です。
AG

これは正しいですが、少なくともSwift 3以降では、intrinsicContentSizeは関数ではなくプロパティであるため、「override func組み込み型ContentSize」ではなく「override var組み込み型ContentSize:CGFloat {}」にする必要があります。
ジョーイ2017年

4

他の回答と同様に、バグを修正します。label.width自動レイアウトで制御されている場合、テキストが切り取られることがあります。

@IBDesignable
class InsetLabel: UILabel {

    @IBInspectable var topInset: CGFloat = 4.0
    @IBInspectable var leftInset: CGFloat = 4.0
    @IBInspectable var bottomInset: CGFloat = 4.0
    @IBInspectable var rightInset: CGFloat = 4.0

    var insets: UIEdgeInsets {
        get {
            return UIEdgeInsets.init(top: topInset, left: leftInset, bottom: bottomInset, right: rightInset)
        }
        set {
            topInset = newValue.top
            leftInset = newValue.left
            bottomInset = newValue.bottom
            rightInset = newValue.right
        }
    }

    override func sizeThatFits(_ size: CGSize) -> CGSize {
        var adjSize = super.sizeThatFits(size)
        adjSize.width += leftInset + rightInset
        adjSize.height += topInset + bottomInset
        return adjSize
    }

    override var intrinsicContentSize: CGSize {
        let systemContentSize = super.intrinsicContentSize
        let adjustSize = CGSize(width: systemContentSize.width + leftInset + rightInset, height: systemContentSize.height + topInset +  bottomInset) 
        if adjustSize.width > preferredMaxLayoutWidth && preferredMaxLayoutWidth != 0 {
            let constraintSize = CGSize(width: bounds.width - (leftInset + rightInset), height: .greatestFiniteMagnitude)
            let newSize = super.sizeThatFits(constraintSize)
            return CGSize(width: systemContentSize.width, height: ceil(newSize.height) + topInset + bottomInset)
        } else {
            return adjustSize
        }
    }

    override func drawText(in rect: CGRect) {
        super.drawText(in: rect.inset(by: insets))
    }
}

2

簡単なパディング(Swift 3.0、Alvin Georgeの回答):

  class NewLabel: UILabel {

        override func textRect(forBounds bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect {
                return self.bounds.insetBy(dx: CGFloat(15.0), dy: CGFloat(15.0))
        }

        override func draw(_ rect: CGRect) {
                super.drawText(in: self.bounds.insetBy(dx: CGFloat(5.0), dy: CGFloat(5.0)))
        }

  }

2

ムンディの答えの詳細。

つまり、ラベルをに埋め込み、UIView自動レイアウトを介してパディングを強制します。例:

パディングされたUILabelのように見える

概要:

1)UIView(「パネル」)を作成し、その外観を設定します。

2)を作成UILabelしてパネルに追加します。

3)制約を追加してパディングを適用します。

4)パネルをビュー階層に追加してから、パネルを配置します。

詳細:

1)パネルビューを作成します。

let panel = UIView()
panel.backgroundColor = .green
panel.layer.cornerRadius = 12

2)ラベルを作成し、サブビューとしてパネルに追加します。

let label = UILabel()
panel.addSubview(label)

3)ラベルの端とパネルの間に制約を追加します。これにより、パネルはラベルから距離を保つようになります。つまり「パディング」

社説:これらすべてを手作業で行うのは、面倒で冗長でエラーが発生しやすい作業です。githubからAuto Layoutラッパーを選択するか、自分で作成することをお勧めします

label.panel.translatesAutoresizingMaskIntoConstraints = false
label.topAnchor.constraint(equalTo: panel.topAnchor,
    constant: vPadding).isActive = true
label.bottomAnchor.constraint(equalTo: panel.bottomAnchor,
    constant: -vPadding).isActive = true
label.leadingAnchor.constraint(equalTo: panel.leadingAnchor,
    constant: hPadding).isActive = true
label.trailingAnchor.constraint(equalTo: panel.trailingAnchor,
    constant: -hPadding).isActive = true

label.textAlignment = .center

4)パネルをビュー階層に追加してから、配置制約を追加します。たとえば、サンプル画像のように、tableViewCellの右側をハグします。

注:寸法拘束ではなく、位置拘束のみを追加する必要があります。自動レイアウトはintrinsicContentSize、ラベルと以前に追加した拘束の両方に基づいてレイアウトを解決します。

hostView.addSubview(panel)
panel.translatesAutoresizingMaskIntoConstraints = false
panel.trailingAnchor.constraint(equalTo: hostView.trailingAnchor,
    constant: -16).isActive = true
panel.centerYAnchor.constraint(equalTo: hostView.centerYAnchor).isActive = true

2

パディングの適用中にテキストのトリミングの問題が発生している場合は、このコードを使用してください。

@IBDesignable class PaddingLabel: UILabel {

    @IBInspectable var topInset: CGFloat = 5.0
    @IBInspectable var bottomInset: CGFloat = 5.0
    @IBInspectable var leftInset: CGFloat = 5.0
    @IBInspectable var rightInset: CGFloat = 5.0

    override func drawText(in rect: CGRect) {
        let insets = UIEdgeInsets.init(top: topInset, left: leftInset, bottom: bottomInset, right: rightInset)
        super.drawText(in: UIEdgeInsetsInsetRect(rect, insets))
    }

    override var intrinsicContentSize: CGSize {
        var intrinsicSuperViewContentSize = super.intrinsicContentSize
        let textWidth = frame.size.width - (self.leftInset + self.rightInset)
        let newSize = self.text!.boundingRect(with: CGSize(textWidth, CGFloat.greatestFiniteMagnitude), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSFontAttributeName: self.font], context: nil)
        intrinsicSuperViewContentSize.height = ceil(newSize.size.height) + self.topInset + self.bottomInset
        return intrinsicSuperViewContentSize
    }
}

extension CGSize{
    init(_ width:CGFloat,_ height:CGFloat) {
        self.init(width:width,height:height)
    }
}

投稿いただきありがとうございます。パディングとトリミングに関する解決策を探しています。あなたの解決策は私が必要とするlabel.numberOfLines = 0を壊すようです。回避策はありますか?
Don

1

他の回答と同様ですが、パディングを動的にセットアップするfuncクラスを使用します。

class UILabelExtendedView: UILabel
{
    var topInset: CGFloat = 4.0
    var bottomInset: CGFloat = 4.0
    var leftInset: CGFloat = 8.0
    var rightInset: CGFloat = 8.0

    override func drawText(in rect: CGRect)
    {
        let insets: UIEdgeInsets = UIEdgeInsets(top: topInset, left: leftInset, bottom: bottomInset, right: rightInset)
        super.drawText(in: UIEdgeInsetsInsetRect(rect, insets))
    }

    override public var intrinsicContentSize: CGSize
    {
        var contentSize = super.intrinsicContentSize
        contentSize.height += topInset + bottomInset
        contentSize.width += leftInset + rightInset
        return contentSize
    }

    func setPadding(top: CGFloat, left: CGFloat, bottom: CGFloat, right: CGFloat){
        self.topInset = top
        self.bottomInset = bottom
        self.leftInset = left
        self.rightInset = right
        let insets: UIEdgeInsets = UIEdgeInsets(top: top, left: left, bottom: bottom, right: right)
        super.drawText(in: UIEdgeInsetsInsetRect(self.frame, insets))
    }
}

1

実用的なソリューションの1つは、メインラベルと同じ高さと色の空白のラベルを追加することです。メインラベルの先頭/末尾のスペースをゼロに設定し、垂直方向の中央を揃え、幅を希望のマージンにします。


1

textRectの周りに2pxのパディングを追加する場合は、次のようにします。

let insets = UIEdgeInsets(top: -2, left: -2, bottom: -2, right: -2)
label.frame = UIEdgeInsetsInsetRect(textRect, insets)

textRectとは ラベルフレーム?
Gustavo Baiocchi Costa

1

Storyboardで@IBInspectable / @IBDesignable UILabelを使用したくない、または使用する必要がない場合(いずれにしても、レンダリングが遅すぎると思います)、4つの異なるCGFloatの代わりにUIEdgeInsetsを使用する方がきれいです。

Swift 4.2のコード例:

class UIPaddedLabel: UILabel {
    var padding = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)

    public override func drawText(in rect: CGRect) {
        super.drawText(in: rect.inset(by: padding))
    }

    public override var intrinsicContentSize: CGSize {
        let size = super.intrinsicContentSize
        return CGSize(width: size.width + padding.left + padding.right,
                      height: size.height + padding.top + padding.bottom)
    }
}

1

Objective-C

IB Designable内に機能を実装する、Tai Leの回答に基づいて、Objective-Cバージョンがあります。

これをYourLabel.hに入れます

@interface YourLabel : UILabel

@property IBInspectable CGFloat topInset;
@property IBInspectable CGFloat bottomInset;
@property IBInspectable CGFloat leftInset;
@property IBInspectable CGFloat rightInset;

@end

そして、これはYourLabel.mに入ります

IB_DESIGNABLE

@implementation YourLabel

#pragma mark - Super

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
        self.topInset = 0;
        self.bottomInset = 0;
        self.leftInset = 0;
        self.rightInset = 0;
    }
    return self;
}

- (void)drawTextInRect:(CGRect)rect {
    UIEdgeInsets insets = UIEdgeInsetsMake(self.topInset, self.leftInset, self.bottomInset, self.rightInset);
    [super drawTextInRect:UIEdgeInsetsInsetRect(rect, insets)];
}

- (CGSize)intrinsicContentSize {

    CGSize size = [super intrinsicContentSize];
    return CGSizeMake(size.width + self.leftInset + self.rightInset,
                      size.height + self.topInset + self.bottomInset);
}

@end

その後、XIBまたはストーリーボード内のクラスを指定した後、Interface BuilderでYourLabelインセットを直接変更できます。インセットのデフォルト値はゼロです。


0

簡単な方法

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        self.view.addSubview(makeLabel("my title",x: 0, y: 100, w: 320, h: 30))
    }

    func makeLabel(title:String, x:CGFloat, y:CGFloat, w:CGFloat, h:CGFloat)->UILabel{
        var myLabel : UILabel = UILabel(frame: CGRectMake(x,y,w,h))
        myLabel.textAlignment = NSTextAlignment.Right

        // inser last char to right
        var titlePlus1char = "\(title)1"
        myLabel.text = titlePlus1char
        var titleSize:Int = count(titlePlus1char)-1

        myLabel.textColor = UIColor(red:1.0, green:1.0,blue:1.0,alpha:1.0)
        myLabel.backgroundColor = UIColor(red: 214/255, green: 167/255, blue: 0/255,alpha:1.0)


        // create myMutable String
        var myMutableString = NSMutableAttributedString()

        // create myMutable font
        myMutableString = NSMutableAttributedString(string: titlePlus1char, attributes: [NSFontAttributeName:UIFont(name: "HelveticaNeue", size: 20)!])

        // set margin size
        myMutableString.addAttribute(NSFontAttributeName, value: UIFont(name: "HelveticaNeue", size: 10)!, range: NSRange(location: titleSize,length: 1))

        // set last char to alpha 0
        myMutableString.addAttribute(NSForegroundColorAttributeName, value: UIColor(red:1.0, green:1.0,blue:1.0,alpha:0), range: NSRange(location: titleSize,length: 1))

        myLabel.attributedText = myMutableString

        return myLabel
    }


    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}

0

簡単なパディング:

import UIKit

    class NewLabel: UILabel {

        override func textRectForBounds(bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect {

            return CGRectInset(self.bounds, CGFloat(15.0), CGFloat(15.0))
        }

        override func drawRect(rect: CGRect) {

            super.drawTextInRect(CGRectInset(self.bounds,CGFloat(5.0), CGFloat(5.0)))
        }

    }

下部ページの3.0バージョン
odemolliens

0

スウィフト4+

let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.firstLineHeadIndent = 10

// Swift 4.2++
label.attributedText = NSAttributedString(string: "Your text", attributes: [NSAttributedString.Key.paragraphStyle: paragraphStyle])

// Swift 4.1--
label.attributedText = NSAttributedString(string: "Your text", attributes: [NSAttributedStringKey.paragraphStyle: paragraphStyle])
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.