Додавання місця / прокладки до UILabel


187

У мене є місце, UILabelде я хочу додати місця вгорі і внизу. З мінімальною висотою в обмеженні я змінив його на:

введіть тут опис зображення

EDIT: Для цього я використав:

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

    } 

Але я мушу знайти інший метод, тому що якщо я напишу більше двох рядків, проблема однакова:

введіть тут опис зображення


1
Можливий дублікат текстової межі
— UILabel

Ми нарешті з’ясували, як саме це зробити у всіх динамічних випадках як ідеальна заміна UILabel, що не потребує перепланування або будь-яких інших проблем. PHEW. stackoverflow.com/a/58876988/294884
— Fattie

Відповіді:


122

Якщо ви хочете дотримуватися UILabel, не підкласифікуючи його, Mundi дав вам чітке рішення.

Якщо ж ви хочете уникати обгортання UILabel UIView, ви можете використовувати UITextView, щоб дозволити використання UIEdgeInsets (padding) або підкласу 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)];
}

Ви можете додатково надати своєму новому підкласу UILabel змінні вставки для TOP, LEFT, BOTTOM та RIGHT.

Прикладним кодом може бути:

In .h (OBJ-C)

float topInset, leftInset,bottomInset, rightInset;

In .m (OBJ-C)

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

Редагувати №1:

З того, що я бачив, здається, вам доведеться переосмислити intrinsicContentSize UILabel під час його підкласифікації.

Тому вам слід перекрити intrinsicContentSize на зразок:

- (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

Після трохи пошуків я знайшов цю історію з IPInsetLabel. Якщо жодне з цих рішень не працює, ви можете спробувати.

Правка №3

У цьому питанні було подібне запитання (дублікат).
Повний список доступних рішень див. У відповідь: Поле тексту UILabel


Вибачте, але я вже використовував: `override func drawTextInRect (rect: CGRect) {var insets: UIEdgeInsets = UIEdgeInsets (верх: 0,0, ліворуч: 10,0, знизу: 0,0, праворуч: 10,0) super.drawTextInRect (UIEdgeInsetsInsetRect (rect, inse inse ))} `це не працює, тому що результат однаковий, не працюйте динамічно ..
— Annachiara

Ви пробували з UITextView замість UILabel? Або вам справді потрібно використовувати UILabel?
— nunofmendes

@Annachiara перевірити зміни, які я зробив. Подивіться, чи працює.
— nunofmendes

Гаразд. Чи працювало це перегляд тексту? Вибачте, що не пишу в Swift, але я все ще перебуваю в режимі Obj-C. Моєю метою з цим кодом було допомогти вам дійти певного висновку. Сподіваюся, що так і було.
— nunofmendes

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 не змінюється, внаслідок чого текст стає "..."
— необі

1
@Tai Le, дякую, що поділився, я використав це в перегляді таблиці, я не знаю, чому його обрізання тексту, наприклад. студент стає студентом,
— vishwa.deepak

1
@Tim, можливо, ти мав намір скористатисяmin
— ielyamani

4
Слова попередження тут. Я використовував це рішення в підкласі UILabel. Під час використання цих міток у багаторядковому режимі, у вертикальному UIStackView виникає проблема. Іноді мітка, здається, загортає текст без правильного розміру мітки - тому слово або 2 закінчується відсутнім у кінці рядка. Зараз у мене немає рішення. Я напишу його тут, якщо зроблю. Я витрачав години, роздумуючи над цим питанням, перш ніж довести, що він тут.
— Даррен Блек

1
Для того, щоб це працювало в таких ситуаціях, вам потрібно змінити "setBounds" і встановити self.preferredMaxLayoutWidth на ширину меж, мінус ліві та праві вставки
— Arnoud Barisain-

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 прокладка
— безрезультатна

3
Це не завжди коректно працює з багаторядковими мітками, оскільки коли мітка обчислює її висоту, вона передбачає нульове набивання.
— fhucho

76

Ви можете зробити це правильно від IB:

  1. змінити текст на атрибутивний

приписуваний текст

  1. перейти до випадаючого списку з "..."

введіть тут опис зображення

  1. ви побачите деякі властивості прокладки для рядків, абзаців та тексту відступу першого рядка чи будь-чого, що вам потрібно

введіть тут опис зображення

  1. перевірити результат

введіть тут опис зображення


1
У моїй розгортці я бачу зміни тексту, але коли я запускаю програму. У тексті не відображаються зміни ... T_T .. моя мітка знаходиться у спеціальній комірці, чи є проблеми?
— А. Трехо

1
@ A.Trejo Можливо, ваша власна клітинка встановить властивість мітки під час виконання.
— П’єр-Ів Гільємет

1
Зміни можуть з’являтися на табло, але при запуску програми змін не відбувається.
— Rhenz

4
Це не застосовується, коли ви встановлюєте текст програмно.
— Nij

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

4
Ваше розширення скасує значення 0 на номерOfLines
— Антуан Бодарт

Це чудово, але у мене проблеми з декількома рядками, навіть думав, що я додаю числа рядків 2 або залишаю на 0, він завжди показує один. ви знаєте, як це вирішити?
— Маго Ніколя Паласіос

1
@AntoineBodart вам вдалося вирішити проблему numberOfLines?
— Маго Ніколя Паласіос

@ AntoineBodart, @Mago Nicolas Palacios - вирішено!
— iEvgen Podkorytov

47

Просто використовуйте a UIViewяк нагляд і визначте фіксовану межу для мітки з автоматичним компонуванням.


1
drawTextInRect працює лише на 1 рядок, intrinsicContentSizeне працює з горизонтальною прокладкою. Загорнути UILabel всередину UIView - це хороший шлях
— onmyway133

8
Якщо ви знаходитесь в IB, тепер настав час згадати меню Редактор -> Вставити -> Переглянути. Виберіть спочатку свій UILabel :)
— Грем

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

Чудова порада ... Я б краще зробив це, ніж пішов на продовження.
— Росс

1
Хороший підказник, з великою перевагою, що це також можна зробити у програмі Interface Builder
— Елі

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)

Результат:


Працює, але чи знаєте ви, як змусити його приймати кілька рядків? Просто змініть init на "PaddingLabel (withInsets: 8, 8, 16, 16)"
— Camilo Ortegón

16

Набивання UILabel, повне рішення. Оновлено до 2020 року.

Виявляється, три речі треба зробити.

1. Необхідно зателефонувати textRect # forBounds з новим меншим розміром

2. Необхідно переосмислити малюнокText новим меншим розміром

3. Якщо комірка з динамічним розміром, повинна налаштувати intrinsicContentSize

У типовому прикладі, наведеному нижче, текстовий блок знаходиться у вигляді таблиці, подання стека чи подібної конструкції, що надає йому фіксовану ширину . У прикладі ми хочемо набивання 60,20,20,24.

Таким чином, ми беремо "існуючий" intrinsicContentSize і фактично додаємо 80 до висоти .

Повторювати ...

Ви повинні буквально "отримати" висоту, обчислену "поки що" двигуном, і змінити це значення.

Я вважаю цей процес заплутаним, але саме так він працює. Для мене Apple повинна викласти дзвінок під назвою "на кшталт" попередній розрахунок висоти ".

По-друге, ми повинні фактично використовувати виклик textRect # forBounds з нашим новим меншим розміром .

Отже, у textRect # forBounds ми спочатку робимо розмір меншим, а потім називаємо супер.

Попередження! Ви повинні зателефонувати супер після , а не раніше!

Якщо ви ретельно досліджуєте всі спроби та обговорення на цій сторінці, це саме проблема. Помітьте, що деякі рішення "здаються майже працюючими", але тоді хтось повідомить, що в певних ситуаціях це не вийде. Це дійсно точна причина - заплутано потрібно "зателефонувати супер після цього", а не раніше.

Отже, якщо ви називаєте супер це "в неправильному порядку", воно зазвичай працює, але не для певної довжини тексту .

Ось точний наочний приклад "неправильно робити супер першим":

введіть тут опис зображення

Зауважте, правильність 60,20,20,24, але обчислення розміру насправді невірно, оскільки це було зроблено за схемою "супер перший" у textRect # forBounds.

Виправлено:

Зауважте, що лише зараз движок textRect # forBounds знає, як правильно зробити обчислення :

введіть тут опис зображення

Нарешті!

Знову ж таки, у цьому прикладі UILabel використовується в типовій ситуації, коли фіксується ширина. Отже, в intrinsicContentSize ми повинні "додати" загальну додаткову висоту, яку ми хочемо. (Вам не потрібно жодним чином "додавати" ширину, це було б безглуздо, як це визначено.)

Потім у textRect # forBounds ви отримуєте межі, "запропоновані поки що", шляхом авторозмітки, ви віднімаєте свої поля, і лише потім знову зателефонуєте до двигуна textRect # forBounds, тобто в супер, що дасть результат.

Нарешті і просто в малюнку. Ви, звичайно, малюєте в тому ж меншому полі.

Фу!

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
}

Знову. Зауважте, що відповіді на це та інші питання якості, які є "майже" правильними, зазнають проблеми на першому зображенні вище - "супер не в тому місці" . Ви повинні змусити розмір більше в intrinsicContentSize, а потім у textRect # forBounds спочатку потрібно скоротити межі першої пропозиції, а потім викликати супер.

Підсумок: ви повинні "зателефонувати супер останньою " у textRect # forBounds

У цьому секрет.

Зверніть увагу, що вам не потрібно і не потрібно додатково викликати недійсний, sizeThatFits, needsLayout або будь-який інший примусовий виклик. Правильне рішення повинно працювати належним чином у звичайному циклі витягнення автомашини.


Порада:

Якщо ви працюєте з шрифтами Monospace, ось чудова порада: 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)

ЗАЧЕКАЙТЕ - насправді існує проблема, яку я виявив із цим у деяких випадках. Раніше це була найправильніша відповідь. Я вказав правильну відповідь нижче.
— 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

Згідно з програмою Swift 4.2 (Xcode 10 beta 6) «UIEdgeInsetsInsetRect» застаріла. Я також оголосив класну громадськість, щоб зробити його кориснішим.

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). Ідентифікатор, як змінити його розмір?
— Bogy

1
Я оновив sizeToFit (), щоб він працював із видом для багаторазового використання
— Bogy,

sizeToFit()має бути загальнодоступним, оскільки: "Переважаючий метод екземпляра повинен бути таким же доступним, як і його тип", що
— додається

7

Я трохи відредагував прийняту відповідь. Виникає проблема, коли leftInsetі rightInsetзбільшиться, частина тексту зникне, б / с ширина мітки звузиться, але висота не збільшується як цифра:

етикетка з підкладкою з неправильним внутрішнім розміром вмісту

Щоб вирішити цю проблему, потрібно перерахувати висоту тексту наступним чином:

@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 повністю порушує попереднє визначення функцій. Отже, override func drawTextInRect(rect: CGRect)стає override func drawText(in rect: CGRect)і override func intrinsicContentSize() -> CGSizeстає override var intrinsicContentSize : CGSize Насолоджуйтесь!
— Док

на жаль, я не змусив його працювати. Я спробував з нашим кодом швидким 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

Відмінно, дякую.
— Майк Таверн

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-підклас 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: drawTextInRect - це властивість класу за замовчуванням UILabel, яку ми не можемо змінити за допомогою коду. Найкраща практика підкласи UILabel та додавання необхідних змін кадру. Так чи інакше, це зручно як функція спадкування.
— AG

це правильно, проте, як мінімум, для Swift 3 принаймні, intrinsicContentSize - це не функція, а властивість, тому слід "замінити var intrinsicContentSize: CGFloat {}", а не "переосмислити функцію intrinsicContentSize", лише примітку.
— joey

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, відповідь Елвіна Джорджа):

  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 або написати її самостійно

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, що мені потрібно. Будь-яке вирішення?
— Дон

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

Якщо ви хочете додати 2px прокладки навколо textRect, просто зробіть це:

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

що таке textRect? label.frame?
— Gustavo Baiocchi Costa

1

Якщо ви не хочете або не потребуєте використання @IBInspectable / @IBDesignable UILabel на панелі розкадрів (я думаю, що вони все одно надто повільні), тоді чистіше використовувати UIEdgeInsets замість 4 різних CGFloats.

Приклад коду для 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

Ціль-С

На основі відповіді Tai Le , яка реалізує функцію всередині IB Designable, ось версія 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

Потім ви можете змінювати вставки YourLabel безпосередньо в програмі Interface Builder після введення класу всередині XIB або аркуша розкадрів, значення за замовчуванням для вставки - нульове.


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])
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.