UILabel текстовое поле - PullRequest
       43

UILabel текстовое поле

297 голосов
/ 13 августа 2010

Я пытаюсь установить левую вставку / поле UILabel и не могу найти способ сделать это. У метки есть задний фон, поэтому просто смена источника не поможет. Было бы идеально вставить текст с помощью 10px или около того с левой стороны.

Ответы [ 38 ]

431 голосов
/ 01 марта 2011

Я решил это путем создания подкласса UILabel и переопределения drawTextInRect: следующим образом:

- (void)drawTextInRect:(CGRect)rect {
    UIEdgeInsets insets = {0, 5, 0, 5};
    [super drawTextInRect:UIEdgeInsetsInsetRect(rect, insets)];
}

эквивалент в Swift 3.1:

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

Как вы, наверное, поняли, это адаптация tc. ответ . Он имеет два преимущества перед этим:

  1. нет необходимости запускать его, отправив sizeToFit сообщение
  2. он оставляет рамку с надписью в одиночку - удобно, если у вашей надписи есть фон, и вы не хотите, чтобы это уменьшалось
137 голосов
/ 16 января 2014

Для многострочного текста левое и правое поле можно установить с помощью NSAttributedString.

NSMutableParagraphStyle *style =  [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
style.alignment = NSTextAlignmentJustified;
style.firstLineHeadIndent = 10.0f;
style.headIndent = 10.0f;
style.tailIndent = -10.0f;   

NSAttributedString *attrText = [[NSAttributedString alloc] initWithString:title attributes:@{ NSParagraphStyleAttributeName : style}];  

UILabel * label = [[UILabel alloc] initWithFrame:someFrame];
label.numberOfLines = 0;
label.attributedText = attrText;
86 голосов
/ 10 июля 2013

Лучший подход для добавления отступов к UILabel - это создать подкласс UILabel и добавить свойство edgeInsets. Затем вы установите нужные вставки, и этикетка будет нарисована соответствующим образом.

OSLabel.h

#import <UIKit/UIKit.h>

@interface OSLabel : UILabel

@property (nonatomic, assign) UIEdgeInsets edgeInsets;

@end

OSLabel.m

#import "OSLabel.h"

@implementation OSLabel

- (id)initWithFrame:(CGRect)frame{
    self = [super initWithFrame:frame];
    if (self) {
        self.edgeInsets = UIEdgeInsetsMake(0, 0, 0, 0);
    }
    return self;
}

- (void)drawTextInRect:(CGRect)rect {
    [super drawTextInRect:UIEdgeInsetsInsetRect(rect, self.edgeInsets)];
}

- (CGSize)intrinsicContentSize
{
    CGSize size = [super intrinsicContentSize];
    size.width  += self.edgeInsets.left + self.edgeInsets.right;
    size.height += self.edgeInsets.top + self.edgeInsets.bottom;
    return size;
}

@end
69 голосов
/ 16 июня 2011

Подклассы немного громоздки для такого простого случая. Альтернатива - просто добавить UILabel без заданного фона в UIView с заданным фоном. Установите для метки x значение 10 и сделайте размер внешнего вида на 20 пикселей шире, чем метка.

45 голосов
/ 24 января 2013

Я просто добавил несколько пробелов к тексту:

self.titleLabel.text = [NSString stringWithFormat:@"    %@", self.titleLabel.text];

Ужасно, но эффективно, и не требует подклассов.

Вы также можете попробовать "\ t".Для общего решения, пожалуйста, обратитесь к принятому ответу

43 голосов
/ 25 сентября 2015

С помощью Swift 3 вы можете получить желаемый эффект, создав подкласс UILabel.В этом подклассе вам нужно будет добавить свойство UIEdgeInsets с необходимыми вставками и переопределить метод drawText(in:), свойство intrinsicContentSize (для кода автоматического макета) и / или метод sizeThatFits(_:) (для кода Springs & Struts).

import UIKit

class PaddingLabel: UILabel {

    let padding: UIEdgeInsets

    // Create a new PaddingLabel instance programamtically with the desired insets
    required init(padding: UIEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 10)) {
        self.padding = padding
        super.init(frame: CGRect.zero)
    }

    // Create a new PaddingLabel instance programamtically with default insets
    override init(frame: CGRect) {
        padding = UIEdgeInsets.zero // set desired insets value according to your needs
        super.init(frame: frame)
    }

    // Create a new PaddingLabel instance from Storyboard with default insets
    required init?(coder aDecoder: NSCoder) {
        padding = UIEdgeInsets.zero // set desired insets value according to your needs
        super.init(coder: aDecoder)
    }

    override func drawText(in rect: CGRect) {
        super.drawText(in: UIEdgeInsetsInsetRect(rect, padding))
    }

    // Override `intrinsicContentSize` property for Auto layout code
    override var intrinsicContentSize: CGSize {
        let superContentSize = super.intrinsicContentSize
        let width = superContentSize.width + padding.left + padding.right
        let heigth = superContentSize.height + padding.top + padding.bottom
        return CGSize(width: width, height: heigth)
    }

    // Override `sizeThatFits(_:)` method for Springs & Struts code
    override func sizeThatFits(_ size: CGSize) -> CGSize {
        let superSizeThatFits = super.sizeThatFits(size)
        let width = superSizeThatFits.width + padding.left + padding.right
        let heigth = superSizeThatFits.height + padding.top + padding.bottom
        return CGSize(width: width, height: heigth)
    }

}

В следующем примере показано, как использовать PaddingLabel экземпляры в UIViewController:

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var storyboardAutoLayoutLabel: PaddingLabel!
    let autoLayoutLabel = PaddingLabel(padding: UIEdgeInsets(top: 20, left: 40, bottom: 20, right: 40))
    let springsAndStructsLabel = PaddingLabel(frame: CGRect.zero)
    var textToDisplay = "Lorem ipsum dolor sit er elit lamet."

    override func viewDidLoad() {
        super.viewDidLoad()

        // Set autoLayoutLabel
        autoLayoutLabel.text = textToDisplay
        autoLayoutLabel.backgroundColor = .red
        autoLayoutLabel.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(autoLayoutLabel)
        autoLayoutLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 30).isActive = true
        autoLayoutLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true

        // Set springsAndStructsLabel
        springsAndStructsLabel.text = textToDisplay
        springsAndStructsLabel.backgroundColor = .green
        view.addSubview(springsAndStructsLabel)
        springsAndStructsLabel.frame.origin = CGPoint(x: 30, y: 90)
        springsAndStructsLabel.sizeToFit()

        // Set storyboardAutoLayoutLabel
        storyboardAutoLayoutLabel.text = textToDisplay
        storyboardAutoLayoutLabel.backgroundColor = .blue
    }

    // Link this IBAction to a UIButton or a UIBarButtonItem in Storyboard
    @IBAction func updateLabelText(_ sender: Any) {
        textToDisplay = textToDisplay == "Lorem ipsum dolor sit er elit lamet." ? "Lorem ipsum." : "Lorem ipsum dolor sit er elit lamet."

        // autoLayoutLabel
        autoLayoutLabel.text = textToDisplay

        // springsAndStructsLabel
        springsAndStructsLabel.text = textToDisplay
        springsAndStructsLabel.sizeToFit()

        // storyboardAutoLayoutLabel
        storyboardAutoLayoutLabel.text = textToDisplay
    }

}
35 голосов
/ 20 апреля 2016

Swift версия ответа Recycled Steel + intrinsizeContentSize().

Поддерживается более традиционный стиль установки вставок для других объектов вида со вставками, при этом можно устанавливать вставки в Interface Builder, т.е. вставки устанавливаются кактак программно:

label.inset = UIEdgeInsetsMake(0, 0, 5, 0)

Пожалуйста, дайте мне знать, если есть какие-либо ошибки.

Swift 3

@IBDesignable class InsetLabel: UILabel {
    @IBInspectable var topInset: CGFloat = 0.0
    @IBInspectable var leftInset: CGFloat = 0.0
    @IBInspectable var bottomInset: CGFloat = 0.0
    @IBInspectable var rightInset: CGFloat = 0.0

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

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

    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 {
        var contentSize = super.intrinsicContentSize
        contentSize.width += leftInset + rightInset
        contentSize.height += topInset + bottomInset

        return contentSize
    }
}

Swift 2.2

@IBDesignable class InsetLabel: UILabel {
    @IBInspectable var topInset: CGFloat = 0.0
    @IBInspectable var leftInset: CGFloat = 0.0
    @IBInspectable var bottomInset: CGFloat = 0.0
    @IBInspectable var rightInset: CGFloat = 0.0

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

    override func drawTextInRect(rect: CGRect) {
        super.drawTextInRect(UIEdgeInsetsInsetRect(rect, insets))
    }

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

        return adjSize
    }

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

        return contentSize
    }
}
29 голосов
/ 30 октября 2013

Вы также можете решить эту проблему, инициализируя UILabel с пользовательским фреймом.

    CGRect initialFrame = CGRectMake(0, 0, 100, 100);
    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0, 10, 0, 0);
    CGRect paddedFrame = UIEdgeInsetsInsetRect(initialFrame, contentInsets);

    self.label = [[UILabel alloc] initWithFrame:paddedFrame];

Кивок на CGRect Tricks .

17 голосов
/ 07 марта 2014

Для пользователей Xamarin (с использованием Unified API):

class UIMarginLabel : UILabel
{
    public UIMarginLabel()
    {
    }

    public UIMarginLabel( CGRect frame ) : base( frame )
    {
    }

    public UIEdgeInsets Insets { get; set; }

    public override void DrawText( CGRect rect )
    {
        base.DrawText( Insets.InsetRect( rect ) );
    }
}

А для тех, кто использует оригинальный API MonoTouch:

public class UIMarginLabel : UILabel
{
    public UIEdgeInsets Insets { get; set; }

    public UIMarginLabel() : base()
    {
        Insets = new UIEdgeInsets(0, 0, 0, 0);
    }
    public UIMarginLabel(RectangleF frame) : base(frame)
    {
        Insets = new UIEdgeInsets(0, 0, 0, 0);
    }

    public override void DrawText(RectangleF frame)
    {
        base.DrawText(new RectangleF(
            frame.X + Insets.Left,
            frame.Y + Insets.Top,
            frame.Width - Insets.Left - Insets.Right,
            frame.Height - Insets.Top - Insets.Bottom));
    }
}
14 голосов
/ 20 октября 2015

и @IBDesignable, позволяющие работать с Интерфейсным Разработчиком

Swift 4

//
//  PaddedLabel.swift
//  TrainCentric
//
//  Created by Arsonik
//  https://stackoverflow.com/a/33244365/337934
//

import UIKit

@IBDesignable
class PaddedLabel: UILabel {

    @IBInspectable var inset:CGSize = CGSize(width: 0, height: 0)

    var padding: UIEdgeInsets {
        var hasText:Bool = false
        if let t = self.text?.count, t > 0 {
            hasText = true
        }
        else if let t = attributedText?.length, t > 0 {
            hasText = true
        }

        return hasText ? UIEdgeInsets(top: inset.height, left: inset.width, bottom: inset.height, right: inset.width) : UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
    }

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

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

    override func sizeThatFits(_ size: CGSize) -> CGSize {
        let superSizeThatFits = super.sizeThatFits(size)
        let p = padding
        let width = superSizeThatFits.width + p.left + p.right
        let heigth = superSizeThatFits.height + p.top + p.bottom
        return CGSize(width: width, height: heigth)
    }
}

Swift 2

@IBDesignable
class PaddedLabel: UILabel {

    @IBInspectable var inset:CGSize = CGSize(width: 0, height: 0)

    var padding: UIEdgeInsets {
        var hasText:Bool = false
        if let t = text?.length where t > 0 {
            hasText = true
        }
        else if let t = attributedText?.length where t > 0 {
            hasText = true
        }

        return hasText ? UIEdgeInsets(top: inset.height, left: inset.width, bottom: inset.height, right: inset.width) : UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
    }

    override func drawTextInRect(rect: CGRect) {
        super.drawTextInRect(UIEdgeInsetsInsetRect(rect, padding))
    }

    override func intrinsicContentSize() -> CGSize {
        let superContentSize = super.intrinsicContentSize()
        let p = padding
        let width = superContentSize.width + p.left + p.right
        let heigth = superContentSize.height + p.top + p.bottom
        return CGSize(width: width, height: heigth)
    }

    override func sizeThatFits(size: CGSize) -> CGSize {
        let superSizeThatFits = super.sizeThatFits(size)
        let p = padding
        let width = superSizeThatFits.width + p.left + p.right
        let heigth = superSizeThatFits.height + p.top + p.bottom
        return CGSize(width: width, height: heigth)
    }
}
...