Изменение размеров UILabel для размещения вставок

Я создаю экран для сканирования штрихкодов, и я должен поместить полупрозрачный экран позади некоторых UILabels улучшить видимость против светлых фонов.

Вот то, на что экран похож теперь:

enter image description here

Я выбираю цвет фона на UILabel получить полупрозрачные поля. Я также создал пользовательское UILabel подкласс, чтобы позволить мне устанавливать некоторое дополнение между краем UILabel и текст с помощью этого подхода.

Поскольку Вы видите на экране выше, UILabel не изменяет размер правильно для принятия дополнения. "Дополнение" просто смещает текст, не изменяя ширину маркировки, заставляя текст усечь.

Обе из этих маркировок будут содержать текст произвольных длин, и мне действительно нужно UILabel динамично изменить размер.

Что UILabel метод я могу переопределить для увеличения ширины маркировки и фактора в дополнении?

62
задан 17 June 2017 в 12:11

7 ответов

Вот класс маркировки, который вычисляет размеры правильно. отправленный код находится в Swift 3, но можно также загрузить Swift 2 или Objective C версии.

, Как это работает?

Путем вычисления надлежащего textRect весь из sizeToFit и автоматическая компоновка наполняет работы как ожидалось. Прием должен сначала вычесть вставки, затем вычислить исходные границы маркировки, и наконец добавить вставки снова.

Код

class NRLabel : UILabel {

    var textInsets = UIEdgeInsets.zero {
        didSet { invalidateIntrinsicContentSize() }
    }

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

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

Дополнительный: Соедините интерфейсом с поддержкой Разработчика

, Если Вы хотите установить текстовые вставки в раскадровках, можно использовать следующее расширение для включения Интерфейсной поддержки Разработчика:

@IBDesignable
extension NRLabel {

    // currently UIEdgeInsets is no supported IBDesignable type,
    // so we have to fan it out here:
    @IBInspectable
    var leftTextInset: CGFloat {
        set { textInsets.left = newValue }
        get { return textInsets.left }
    }

    // Same for the right, top and bottom edges.
}

Теперь можно удобно установить вставки в IB и затем просто нажать вЊ ˜ = для корректировки размера маркировки для установки.

Правовая оговорка:

Весь код находится в общественном достоянии. Поступать как угодно.

187
ответ дан 31 October 2019 в 13:09

Вот версия Swift подкласса UILabel (то же как ответ @Nikolai), который создает дополнительное дополнение вокруг текста UILabel:

class EdgeInsetLabel : UILabel {
    var edgeInsets:UIEdgeInsets = UIEdgeInsetsZero

    override func textRectForBounds(bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect {
        var rect = super.textRectForBounds(UIEdgeInsetsInsetRect(bounds, edgeInsets), limitedToNumberOfLines: numberOfLines)

        rect.origin.x -= edgeInsets.left
        rect.origin.y -= edgeInsets.top
        rect.size.width  += (edgeInsets.left + edgeInsets.right);
        rect.size.height += (edgeInsets.top + edgeInsets.bottom);

        return rect
    }

    override func drawTextInRect(rect: CGRect) {
        super.drawTextInRect(UIEdgeInsetsInsetRect(rect, edgeInsets))
    }
}
14
ответ дан 31 October 2019 в 13:09

Вот версия C# (полезна для Xamarin) на основе кода Nikolai:

public class UIEdgeableLabel : UILabel
{
    public UIEdgeableLabel() : base() { }
    public UIEdgeableLabel(NSCoder coder) : base(coder) { }
    public UIEdgeableLabel(CGRect frame) : base(frame) { }
    protected UIEdgeableLabel(NSObjectFlag t) : base(t) { }

    private UIEdgeInsets _edgeInset = UIEdgeInsets.Zero;
    public UIEdgeInsets EdgeInsets
    {
        get { return _edgeInset; }
        set
        {
            _edgeInset = value;
            this.InvalidateIntrinsicContentSize();
        }
    }

    public override CGRect TextRectForBounds(CGRect bounds, nint numberOfLines)
    {
        var rect = base.TextRectForBounds(EdgeInsets.InsetRect(bounds), numberOfLines);
        return new CGRect(x: rect.X - EdgeInsets.Left,
                          y: rect.Y - EdgeInsets.Top,
                          width: rect.Width + EdgeInsets.Left + EdgeInsets.Right,
                          height: rect.Height + EdgeInsets.Top + EdgeInsets.Bottom);
    }

    public override void DrawText(CGRect rect)
    {
        base.DrawText(this.EdgeInsets.InsetRect(rect));
    }
}
4
ответ дан 31 October 2019 в 13:09

Быстро 5 версий ответа Nikolai Ruhe:

extension UIEdgeInsets {
   func apply(_ rect: CGRect) -> CGRect {
      return rect.inset(by: self)
   }
}

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

  override func textRect(forBounds bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect {
    let insetRect = bounds.inset(by: textInsets)
    let textRect = super.textRect(forBounds: insetRect, 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))
  }}
4
ответ дан 31 October 2019 в 13:09

В дополнениях к Nikolai Ruhe ответ, необходимо делать недействительным внутренний размер содержания для авторасположения для надлежащего перевычисления изменений размера. Вы заметили бы эту проблему при изменении edgeInsets по жизненному циклу приложения:

class NRLabel: UILabel {

    var edgeInsets = UIEdgeInsetsZero {
        didSet {
            self.invalidateIntrinsicContentSize()
        }
    }

    ...
}
2
ответ дан 31 October 2019 в 13:09

Вот пример того, что я использовал для простых 10 единиц, дополняющих слева и права на маркировку со скругленными углами. Просто установите текст метки для центрирования, это сам, и сделайте, это - класс IndentedLabel, и остальное заботится о себе. Для изменения дополнения просто увеличиваются или вниз rect.size.width + = (x)

class IndentedLabel: UILabel {

    var edgeInsets:UIEdgeInsets = UIEdgeInsetsZero

    override func textRectForBounds(bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect {
        var rect = super.textRectForBounds(UIEdgeInsetsInsetRect(bounds, edgeInsets), limitedToNumberOfLines: numberOfLines)

        rect.size.width  += 20;

        return rect
    }

    override func drawTextInRect(rect: CGRect) {
        self.clipsToBounds = true
        self.layer.cornerRadius = 3
        super.drawTextInRect(UIEdgeInsetsInsetRect(rect, edgeInsets))
    }
}
0
ответ дан 31 October 2019 в 13:09

Вот быстрое, hacky способ сделать это, что можно понять более быстро. Это не столь устойчиво как Nikolai, но это сделало задание. Я сделал это, когда я пытался приспособить свой текст в моем UILabel в UITableViewCell:

  1. Набор ограничение ширины для Подключения UILabel
  2. ограничение через IBOutlet на Ваш код, любой VC (пользовательский класс ячейки при выполнении расширяющейся ячейки табличного представления)
  3. Создает переменную для фактического размера текста, затем добавляет вставки + размер ширины к ограничению и обновляет представление:

let messageTextSize: CGSize = (messageText as NSString).sizeWithAttributes([ NSFontAttributeName: UIFont.systemFontOfSize(14.0)]) cell.widthConstraint.constant = messageTextSize.width + myInsetsOrWhatever

я еще экстенсивно не протестировал его, Вам, возможно, придется играть вокруг с точными значениями CGFloat, которые Вы добавляете. Я нашел, что правильный размер не является точно шириной плюс вставки; это немного больше, чем это. Это удостоверяется, что ширина UILabel всегда будет, по крайней мере, размером текста или больше.

0
ответ дан 31 October 2019 в 13:09

Другие вопросы по тегам:

Похожие вопросы: