Как контролировать межстрочный интервал в UILabel


275

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



2
Могу ли я предложить вам принять один из правильных ответов для iOS 6.0 и новее? В настоящее время принятый ответ устарел.
Марк Эмери

Для каждой строки используйте новую UILabel, а затем вставьте все метки в StackView. Наконец настроить spacingиз StackView. Не забудьте сложить их вертикально.
Дорогая,

Обратитесь к следующей ссылке для решения в Swift 2. stackoverflow.com/a/39158698/6602495
Снеха

Обратитесь к stackoverflow.com/a/44325650/342794 для настройки раскадровки и других деталей.
Лал

Ответы:


263

Я думал добавить что-то новое к этому ответу, так что я не чувствую себя так плохо ... Вот ответ Swift :

import Cocoa

let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 40

let attrString = NSMutableAttributedString(string: "Swift Answer")
attrString.addAttribute(.paragraphStyle, value:paragraphStyle, range:NSMakeRange(0, attrString.length))

var tableViewCell = NSTableCellView()
tableViewCell.textField.attributedStringValue = attrString

«Краткий ответ: вы не можете. Чтобы изменить расстояние между строками текста, вам нужно будет создать подкласс UILabel и создать свой собственный drawTextInRect или создать несколько меток».

Смотрите: Установка межстрочного интервала UILabel


Это действительно старый ответ, и другие уже добавили новый и лучший способ справиться с этим. Пожалуйста, ознакомьтесь с последними ответами, представленными ниже.


23
Начиная с iOS 6.0, вы можете управлять им через NSAttributedString(также доступно в свойствах UILable в конструкторе интерфейса Xcode).
2012 года

13
Интересно, что, насколько я могу судить, вы можете добавить дополнительный интервал между строками, но не уменьшать его NSParagraphStyleпри использовании NSAttributedString. (Мне может потребоваться провести дополнительное тестирование других изменяемых свойств, но lineSpacingсвойство позволяет только увеличить его.)
livingtech

см. мой ответ, чтобы увидеть способ использования NSAttributedString
d.ennis

2
@livingtech Это бесит, и я верю, что ты прав. Вы нашли какие-нибудь обходные пути?
Дом Виньярд

7
Просто чтобы уточнить что-то в этой теме. Если вы хотите уменьшить межстрочный интервал, установите высоту строки на 1,0, а затем установите LineHeightMultiple на более низкое значение <1,0, например: [paraStyle setLineHeightMultiple: 0,8] или
paraStyle.lineHeightMultiple

401

В Xcode 6 вы можете сделать это в раскадровке:

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


1
Возьмите больше преимуществ раскадровки!
Аллен

22
У @PaperThick та же проблема в 6.1.1. Это «Гарлем Шейк» за несколько минут. Не знает, как это исправить :) Xcode Shaking
Антон Гаенко

8
Есть ли способ установить пользовательские шрифты таким образом? Я не могу изменить этот helvetica neue на любой другой шрифт.
Маркос Курвелло

2
Если вы включите «Атрибут», а затем откроете файл как исходный код, вы сможете вручную редактировать «lineHeightMultiple» и, следовательно, обойти ошибку Harlem Shake
ED-209

2
@azdev для тех, кто все еще смотрит на это, у меня больше шатаний в Xcode 7.3, но я думаю, что это первая версия, где это не было проблемой
LulzCow

103

Начиная с iOS 6 вы можете установить атрибутивную строку для UILabel. Проверьте следующее:

NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:label.text];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineSpacing = spacing;
[attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, label.text.length)];

label.attributedText = attributedString;

1
attributedStringДолжно быть NSMutableAttributedString(не NSAttributedString)
Mike S

14
Код первой строки должен бытьNSMutableAttributedString *attributedString = [NSMutableAttributedString alloc]initWithString:@"sample text"];
Аллен

lineSpacingСобственность NSMutableParagraphStyleникогда не бывает отрицательная, поэтому высота линии не может быть уменьшена с этим подходом. Чтобы ответить на вопрос, вы должны использовать другое свойство, см. @ D.ennis answer.
Тео

81

Решения, изложенные здесь, не работают для меня. Я нашел немного другой способ сделать это с помощью iOS 6 NSAttributeString:

myLabel.numberOfLines = 0; 
NSString* string = @"String with line one. \n Line two. \n Line three.";
NSMutableParagraphStyle *style  = [[NSMutableParagraphStyle alloc] init];
style.minimumLineHeight = 30.f;
style.maximumLineHeight = 30.f;
NSDictionary *attributtes = @{NSParagraphStyleAttributeName : style,};
myLabel.attributedText = [[NSAttributedString alloc] initWithString:string
                                                         attributes:attributtes];   
[myLabel sizeToFit];

1
Высота строки зависит от размера шрифта. Межстрочный интервал - это просто межстрочный интервал. Вы можете заставить вещи работать, просто установив минимальную / максимальную высоту строки, но это только потому, что текущие размеры шрифтов, которые вы используете, не превышают границы высоты строки. Согласно документации: «... глифы и графики, превышающие эту высоту, будут перекрывать соседние линии ... Хотя это ограничение применяется к самой линии, межстрочный интервал добавляет дополнительное пространство между соседними линиями».
Ари Брагинский

+1, если вы хотите уменьшить расстояние между строками, это то, что вы хотите сделать. По умолчанию реальный межстрочный интервал, скорее всего, равен 0, поэтому люди сообщают, что вы можете только увеличить его. Проблема слишком большого расстояния возникает из-за того, что высота линии слишком велика, поэтому она будет выполнять работу в 99% случаев.
Lawicko

1
Это единственный ответ, который я смог найти, который использует фактическое значение высоты строки (а не соотношение), общее для таких дизайнерских приложений, как Photoshop, Sketch, CSS и т. Д.
Albert Bori

35

Я сделал это простое расширение, которое очень хорошо работает для меня:

extension UILabel {
    func setLineHeight(lineHeight: CGFloat) {
        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.lineSpacing = 1.0
        paragraphStyle.lineHeightMultiple = lineHeight
        paragraphStyle.alignment = self.textAlignment

        let attrString = NSMutableAttributedString()
        if (self.attributedText != nil) {
            attrString.append( self.attributedText!)
        } else {
            attrString.append( NSMutableAttributedString(string: self.text!))
            attrString.addAttribute(NSAttributedStringKey.font, value: self.font, range: NSMakeRange(0, attrString.length))
        }
        attrString.addAttribute(NSAttributedStringKey.paragraphStyle, value:paragraphStyle, range:NSMakeRange(0, attrString.length))
        self.attributedText = attrString
    }
}

Скопируйте это в файл, так что вы можете использовать его следующим образом

myLabel.setLineHeight(0.7)

помните, что если вы делаете это, когда вы также используете раскадровку для этого ярлыка, то обязательно установите для линий ярлыка значение 0
Honey

Почему бы вам просто не установить lineSpacingи не забыть об установке lineHeightMultiple?
Мед

Поскольку ключ для уменьшения высоты строки - это lineHeightMultiple, без lineSpacing
Agustin Meriles

скажем, вы хотите, чтобы высота строки была 1,4, почему вы не можете просто написать .lineSpacing = 1.4и забыть все о .lineHeightMultiple...
Дорогая

Хах! Я пытался, и я не работал, но мне интересно, почему я не вижу здесь других ответов, не использующих ваш механизм, я имею в виду, что они просто устанавливают lineSpacing. Смотрите принятый ответ ...
Дорогая

33

Из Интерфейсного Разработчика (Раскадровка / XIB):

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

Программный:

SWift 4

Использование расширения метки

extension UILabel {

    // Pass value for any one of both parameters and see result
    func setLineSpacing(lineSpacing: CGFloat = 0.0, lineHeightMultiple: CGFloat = 0.0) {

        guard let labelText = self.text else { return }

        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.lineSpacing = lineSpacing
        paragraphStyle.lineHeightMultiple = lineHeightMultiple

        let attributedString:NSMutableAttributedString
        if let labelattributedText = self.attributedText {
            attributedString = NSMutableAttributedString(attributedString: labelattributedText)
        } else {
            attributedString = NSMutableAttributedString(string: labelText)
        }

        // Line spacing attribute
        attributedString.addAttribute(NSAttributedStringKey.paragraphStyle, value:paragraphStyle, range:NSMakeRange(0, attributedString.length))

        self.attributedText = attributedString
    }
}

Теперь вызовите функцию расширения

let label = UILabel()
let stringValue = "How to\ncontrol\nthe\nline spacing\nin UILabel"

// Pass value for any one argument - lineSpacing or lineHeightMultiple
label.setLineSpacing(lineSpacing: 2.0) .  // try values 1.0 to 5.0

// or try lineHeightMultiple
//label.setLineSpacing(lineHeightMultiple = 2.0) // try values 0.5 to 2.0

Или используя экземпляр метки (просто скопируйте и выполните этот код, чтобы увидеть результат)

let label = UILabel()
let stringValue = "How to\ncontrol\nthe\nline spacing\nin UILabel"
let attrString = NSMutableAttributedString(string: stringValue)
var style = NSMutableParagraphStyle()
style.lineSpacing = 24 // change line spacing between paragraph like 36 or 48
style.minimumLineHeight = 20 // change line spacing between each line like 30 or 40

// Line spacing attribute
attrString.addAttribute(NSAttributedStringKey.paragraphStyle, value: style, range: NSRange(location: 0, length: stringValue.characters.count))

// Character spacing attribute
attrString.addAttribute(NSAttributedStringKey.kern, value: 2, range: NSMakeRange(0, attrString.length))

label.attributedText = attrString

Свифт 3

let label = UILabel()
let stringValue = "How to\ncontrol\nthe\nline spacing\nin UILabel"
let attrString = NSMutableAttributedString(string: stringValue)
var style = NSMutableParagraphStyle()
style.lineSpacing = 24 // change line spacing between paragraph like 36 or 48
style.minimumLineHeight = 20 // change line spacing between each line like 30 or 40
attrString.addAttribute(NSParagraphStyleAttributeName, value: style, range: NSRange(location: 0, length: stringValue.characters.count))
label.attributedText = attrString

2
Добавьте строку "paraStyle.alignment = self.textAlignment", чтобы сохранить исходное выравнивание. В противном случае текст будет выровнен по левому краю.
Нитин Майкл

Для тех, кто теряет многоточие на больших текстах, используйте: paraStyle.lineBreakMode = .byTruncatingTail
christostsang

19

В iOS 6 теперь есть альтернативный ответ, который заключается в том, чтобы установитьтрибуття на атрибуте, используя NSAttributedString с соответствующими стилями абзаца. Посмотрите этот ответ переполнения стека для деталей относительно высоты строки с NSAttributedString:

Основной текст - NSAttributedString высота строки сделано правильно?



12

В Swift и как функция, вдохновленная DarkDust

// Usage: setTextWithLineSpacing(myEpicUILabel,text:"Hello",lineSpacing:20)
func setTextWithLineSpacing(label:UILabel,text:String,lineSpacing:CGFloat)
{
    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.lineSpacing = lineSpacing

    let attrString = NSMutableAttributedString(string: text)
    attrString.addAttribute(NSAttributedString.Key.paragraphStyle, value:paragraphStyle, range:NSMakeRange(0, attrString.length))

    label.attributedText = attrString
}

7

Согласно @Mike's Answer, lineHeightMultipleключевым моментом является снижение . Пример ниже, он хорошо работает для меня:

    NSString* text = label.text;
    CGFloat textWidth = [text sizeWithAttributes:@{NSFontAttributeName: label.font}].width;
    if (textWidth > label.frame.size.width) {
        NSMutableParagraphStyle *paragraph = [[NSMutableParagraphStyle alloc] init];
        paragraph.alignment = NSTextAlignmentCenter;
        paragraph.lineSpacing = 1.0f;
        paragraph.lineHeightMultiple = 0.75;     // Reduce this value !!!
        NSMutableAttributedString* attrText = [[NSMutableAttributedString alloc] initWithString:text];
        [attrText addAttribute:NSParagraphStyleAttributeName value:paragraph range:NSMakeRange(0, text.length)];
        label.attributedText = attrText;
    }

6

SWIFT 3 полезное расширение для более удобного задания пространства между строками :)

extension UILabel
{
    func setLineHeight(lineHeight: CGFloat)
    {
        let text = self.text
        if let text = text 
        {

            let attributeString = NSMutableAttributedString(string: text)
            let style = NSMutableParagraphStyle()

           style.lineSpacing = lineHeight
           attributeString.addAttribute(NSParagraphStyleAttributeName,
                                        value: style,
                                        range: NSMakeRange(0, text.characters.count))

           self.attributedText = attributeString
        }
    }
}

5

Я нашел способ, где вы можете установить реальную высоту строки (не фактор), и он даже отображает в реальном времени в Интерфейсном Разработчике . Просто следуйте инструкциям ниже. Код написан на Swift 4 .


Шаг № 1: Создайте файл с именем DesignableLabel.swiftи вставьте следующий код:

import UIKit

@IBDesignable
class DesignableLabel: UILabel {
    @IBInspectable var lineHeight: CGFloat = 20 {
        didSet {
            let paragraphStyle = NSMutableParagraphStyle()
            paragraphStyle.minimumLineHeight = lineHeight
            paragraphStyle.maximumLineHeight = lineHeight
            paragraphStyle.alignment = self.textAlignment

            let attrString = NSMutableAttributedString(string: text!)
            attrString.addAttribute(NSAttributedStringKey.font, value: font, range: NSRange(location: 0, length: attrString.length))
            attrString.addAttribute(NSAttributedStringKey.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: attrString.length))
            attributedText = attrString
        }
    }
}

Шаг № 2: Поместите объект UILabelв раскадровку / XIB и установите для него класс DesignableLabel. Подождите, пока ваш проект для сборки (сборка должна быть успешной!).

Указание класса для вашей UILabel


Шаг 3: Теперь вы должны увидеть новое свойство на панели свойств с именем «Высота строки». Просто установите значение, которое вам нравится, и вы должны увидеть результаты немедленно!

Установить высоту линии в свойствах


2

Вот подкласс UILabel, который устанавливает lineHeightMultipleи гарантирует, что внутренняя высота достаточно велика, чтобы не обрезать текст.

@IBDesignable
class Label: UILabel {
    override var intrinsicContentSize: CGSize {
        var size = super.intrinsicContentSize
        let padding = (1.0 - lineHeightMultiple) * font.pointSize
        size.height += padding
        return size
    }

    override var text: String? {
        didSet {
            updateAttributedText()
        }
    }

    @IBInspectable var lineHeightMultiple: CGFloat = 1.0 {
        didSet {
            updateAttributedText()
        }
    }

    private func updateAttributedText() {
        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.lineHeightMultiple = lineHeightMultiple
        attributedText = NSAttributedString(string: text ?? "", attributes: [
            .font: font,
            .paragraphStyle: paragraphStyle,
            .foregroundColor: textColor
        ])
        invalidateIntrinsicContentSize()
    }
}

дополнительный отступ должен быть (lineHeightMultiple - 1.0) * font.pointSize, верно?
Павел Алексеев

Код выше, как-будто, работает для меня. Но, возможно, вы правы. Вы пробовали свои изменения? @PavelAlexeev
phatmann

Нет, я придерживаюсь lineSpacing вместо lineHeightMultiple :)
Павел Алексеев

1

В Swift 2.0 ...

Добавить расширение:

extension UIView {
    func attributesWithLineHeight(font: String, color: UIColor, fontSize: CGFloat, kern: Double, lineHeightMultiple: CGFloat) -> [String: NSObject] {
        let titleParagraphStyle = NSMutableParagraphStyle()
        titleParagraphStyle.lineHeightMultiple = lineHeightMultiple

        let attribute = [
            NSForegroundColorAttributeName: color,
            NSKernAttributeName: kern,
            NSFontAttributeName : UIFont(name: font, size: fontSize)!,
            NSParagraphStyleAttributeName: titleParagraphStyle
        ]
        return attribute
    }
}

Теперь просто установите свой UILabel как attribuText:

self.label.attributedText = NSMutableAttributedString(string: "SwiftExample", attributes: attributesWithLineHeight("SourceSans-Regular", color: UIColor.whiteColor(), fontSize: 20, kern: 2.0, lineHeightMultiple: 0.5))    

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


1

Swift3 - в расширении UITextView или UILabel добавьте эту функцию:

Я добавил некоторый код для сохранения текущего атрибутивного текста, если вы уже используете атрибутивные строки с представлением (вместо того, чтобы перезаписывать их).

func setLineHeight(_ lineHeight: CGFloat) {
    guard let text = self.text, let font = self.font else { return }

    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.lineSpacing = 1.0
    paragraphStyle.lineHeightMultiple = lineHeight
    paragraphStyle.alignment = self.textAlignment

    var attrString:NSMutableAttributedString
    if let attributed = self.attributedText {
        attrString = NSMutableAttributedString(attributedString: attributed)
    } else {
        attrString = NSMutableAttributedString(string: text)
        attrString.addAttribute(NSFontAttributeName, value: font, range: NSMakeRange(0, attrString.length))
    }
    attrString.addAttribute(NSParagraphStyleAttributeName, value:paragraphStyle, range:NSMakeRange(0, attrString.length))
    self.attributedText = attrString
}

1

Другой ответ ... Если вы передаете строку программно, вам нужно передать приписанную строку вместо обычной строки и изменить ее стиль. (IOS10)

NSMutableAttributedString * attrString = [[NSMutableAttributedString alloc] initWithString:@"Your \nregular \nstring"];
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
[style setLineSpacing:4];
[attrString addAttribute:NSParagraphStyleAttributeName
                   value:style
                   range:NSMakeRange(0, attrString.length)];
_label.attributedText = attrString;

1

Расширение Swift 3:

    import UIKit

extension UILabel {
    func setTextWithLineSpacing(text: String, lineHeightMultiply: CGFloat = 1.3) {
        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.lineHeightMultiple = lineHeightMultiply
        paragraphStyle.alignment = .center
        let attributedString = NSMutableAttributedString(string: text)
        attributedString.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: NSRange(location: 0, length: attributedString.length))
        self.attributedText = attributedString
    }
}

1

Это должно помочь с этим. Затем вы можете назначить свой ярлык этому пользовательскому классу в раскадровке и использовать его параметры непосредственно в свойствах:

open class SpacingLabel : UILabel {

    @IBInspectable open var lineHeight:CGFloat = 1 {
        didSet {
            let paragraphStyle = NSMutableParagraphStyle()
            paragraphStyle.lineSpacing = 1.0
            paragraphStyle.lineHeightMultiple = self.lineHeight
            paragraphStyle.alignment = self.textAlignment

            let attrString = NSMutableAttributedString(string: self.text!)
            attrString.addAttribute(NSAttributedStringKey.font, value: self.font, range: NSMakeRange(0, attrString.length))
            attrString.addAttribute(NSAttributedStringKey.paragraphStyle, value:paragraphStyle, range:NSMakeRange(0, attrString.length))
            self.attributedText = attrString
        }
    } 
}

Это должно помочь с этим. Затем вы можете назначить свой ярлык этому пользовательскому классу в раскадровке и использовать его параметры непосредственно в свойствах.
Рассел Уорик

пожалуйста, не помещайте содержание, связанное с вашим ответом в комментариях. Ваш ответ должен быть полезным без необходимости читать комментарии
Нейрон

1

Расширение Swift 4 label. Создание NSMutableAttributedString перед передачей в функцию в случае, если для приписанного текста требуются дополнительные атрибуты.

extension UILabel {

    func setLineHeightMultiple(to height: CGFloat, withAttributedText attributedText: NSMutableAttributedString) {

        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.lineSpacing = 1.0
        paragraphStyle.lineHeightMultiple = height
        paragraphStyle.alignment = textAlignment

        attributedText.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: attributedText.length - 1))

        self.attributedText = attributedText
    }
}

0

Этот код работал для меня (ios 7 и ios 8 наверняка).

_label.numberOfLines=2;
_label.textColor=[UIColor whiteColor];

NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineHeightMultiple=0.5;
paragraphStyle.alignment = NSTextAlignmentCenter;
paragraphStyle.lineSpacing = 1.0;

NSDictionary *nameAttributes=@{
                               NSParagraphStyleAttributeName : paragraphStyle,
                               NSBaselineOffsetAttributeName:@2.0
                               };


NSAttributedString *string=[[NSAttributedString alloc] initWithString:@"22m\nago" attributes:nameAttributes];
_label.attributedText=string;

0

Вот мое решение в быстрой. Подкласс должен работать как для атрибута attributeText и text, так и для characterSpacing + lineSpacing. Он сохраняет интервал, если установлена ​​новая строка или attributeString.

open class UHBCustomLabel : UILabel {
    @IBInspectable open var characterSpacing:CGFloat = 1 {
        didSet {
            updateWithSpacing()
        }

    }
    @IBInspectable open var lines_spacing:CGFloat = -1 {
        didSet {
            updateWithSpacing()
        }

    }
    open override var text: String? {
        set {
            super.text = newValue
            updateWithSpacing()
        }
        get {
            return super.text
        }
    }
    open override var attributedText: NSAttributedString? {
        set {
            super.attributedText = newValue
            updateWithSpacing() 
        }
        get {
            return super.attributedText
        }
    }
    func updateWithSpacing() {
        let attributedString = self.attributedText == nil ? NSMutableAttributedString(string: self.text ?? "") : NSMutableAttributedString(attributedString: attributedText!)
        attributedString.addAttribute(NSKernAttributeName, value: self.characterSpacing, range: NSRange(location: 0, length: attributedString.length))
        if lines_spacing >= 0 {
            let paragraphStyle = NSMutableParagraphStyle()
            paragraphStyle.lineSpacing = lines_spacing
            paragraphStyle.alignment = textAlignment
            attributedString.addAttribute(NSParagraphStyleAttributeName, value:paragraphStyle, range:NSMakeRange(0, attributedString.length))
        }
        super.attributedText = attributedString
    }
}

-5

Как быстро-грязный-умный-простой обходной путь:

Для UILabels, у которых мало строк, вы можете вместо этого использовать stackViews.

  1. Для каждой строки напишите новый ярлык.
  2. Вставьте их в StackView. (Выберите обе метки -> Редактор -> Внедрить -> StackView
  3. Настройте SpacingStackView на нужное вам количество.

Обязательно сложите их вертикально . Это решение также работает для пользовательских шрифтов.

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


FWIW это ужасное, но работоспособное решение. Поэтому я сохраняю это.
Мед

Я также видел принцип, по которому разработчики iOS используют стеки для создания графиков. Stackviews очень мощные
Honey
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.