Как сделать атрибутивную строку с помощью Swift?

247

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

Я просмотрел документацию для присваиваемой строки, и я даже уменьшил "Attributed String Creator" из магазина приложений, но полученный код находится в Objective-C, и я использую Swift. Что было бы удивительным и, вероятно, полезным для других разработчиков, изучающих этот язык, является ярким примером создания настраиваемого шрифта с пользовательскими атрибутами с использованием атрибутной строки в Swift. Документация для этого очень запутанна, так как нет четкого пути к тому, как это сделать. Мой план состоит в том, чтобы создать атрибутную строку и добавить ее в конец моей строки coffeeAmount.

var coffeeAmount: String = calculatedCoffee + attributedText

Где calculateCoffee - Int, преобразованный в строку, и "attributedText" - это строчный "g" с настраиваемым шрифтом, который я пытаюсь создать. Возможно, я ошибаюсь. Любая помощь приветствуется!

Теги:
fonts
uilabel
nsattributedstring

22 ответа

877

Изображение 1687

Этот ответ был обновлен для Swift 4.2.

Краткий справочник

Общая форма создания и установки приписанной строки выглядит следующим образом. Вы можете найти другие общие варианты ниже.

// create attributed string
let myString = "Swift Attributed String"
let myAttribute = [ NSAttributedString.Key.foregroundColor: UIColor.blue ]
let myAttrString = NSAttributedString(string: myString, attributes: myAttribute) 

// set attributed text on a UILabel
myLabel.attributedText = myAttrString

Изображение 1688

let myAttribute = [ NSAttributedString.Key.foregroundColor: UIColor.blue ]

Изображение 1689

let myAttribute = [ NSAttributedString.Key.backgroundColor: UIColor.yellow ]

Изображение 1690

let myAttribute = [ NSAttributedString.Key.font: UIFont(name: "Chalkduster", size: 18.0)! ]

Изображение 1691

let myAttribute = [ NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue ]

Изображение 1692

let myShadow = NSShadow()
myShadow.shadowBlurRadius = 3
myShadow.shadowOffset = CGSize(width: 3, height: 3)
myShadow.shadowColor = UIColor.gray

let myAttribute = [ NSAttributedString.Key.shadow: myShadow ]

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


Атрибуты

Строковые атрибуты - это просто словарь в форме [NSAttributedString.Key: Any], где NSAttributedString.Key - это имя ключа атрибута, а Any - значение некоторого типа. Значением может быть шрифт, цвет, целое число или что-то еще. В Swift есть много стандартных атрибутов, которые уже были предопределены. Например:

  • имя ключа: NSAttributedString.Key.font, значение: UIFont
  • имя ключа: NSAttributedString.Key.foregroundColor, значение: UIColor
  • имя ключа: NSAttributedString.Key.link, значение: NSURL или NSString

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

  • имя ключа: NSAttributedString.Key.myName, значение: некоторый тип.
    если вы делаете расширение:

    extension NSAttributedString.Key {
        static let myName = NSAttributedString.Key(rawValue: "myCustomAttributeKey")
    }
    

Создание атрибутов в Swift

Вы можете объявить атрибуты так же, как и любой другой словарь.

// single attributes declared one at a time
let singleAttribute1 = [ NSAttributedString.Key.foregroundColor: UIColor.green ]
let singleAttribute2 = [ NSAttributedString.Key.backgroundColor: UIColor.yellow ]
let singleAttribute3 = [ NSAttributedString.Key.underlineStyle: NSUnderlineStyle.double.rawValue ]

// multiple attributes declared at once
let multipleAttributes: [NSAttributedString.Key : Any] = [
    NSAttributedString.Key.foregroundColor: UIColor.green,
    NSAttributedString.Key.backgroundColor: UIColor.yellow,
    NSAttributedString.Key.underlineStyle: NSUnderlineStyle.double.rawValue ]

// custom attribute
let customAttribute = [ NSAttributedString.Key.myName: "Some value" ]

Обратите внимание на rawValue который был необходим для значения стиля подчеркивания.

Поскольку атрибуты являются просто словарями, их также можно создать, создав пустой словарь и добавив в него пары ключ-значение. Если значение будет содержать несколько типов, вы должны использовать Any в качестве типа. Вот пример multipleAttributes атрибутов сверху, воссозданный таким образом:

var multipleAttributes = [NSAttributedString.Key : Any]()
multipleAttributes[NSAttributedString.Key.foregroundColor] = UIColor.green
multipleAttributes[NSAttributedString.Key.backgroundColor] = UIColor.yellow
multipleAttributes[NSAttributedString.Key.underlineStyle] = NSUnderlineStyle.double.rawValue

Приписанные Строки

Теперь, когда вы понимаете атрибуты, вы можете создавать атрибутные строки.

инициализация

Есть несколько способов создания приписанных строк. Если вам просто нужна строка только для чтения, вы можете использовать NSAttributedString. Вот несколько способов его инициализации:

// Initialize with a string only
let attrString1 = NSAttributedString(string: "Hello.")

// Initialize with a string and inline attribute(s)
let attrString2 = NSAttributedString(string: "Hello.", attributes: [NSAttributedString.Key.myName: "A value"])

// Initialize with a string and separately declared attribute(s)
let myAttributes1 = [ NSAttributedString.Key.foregroundColor: UIColor.green ]
let attrString3 = NSAttributedString(string: "Hello.", attributes: myAttributes1)

Если вам потребуется изменить атрибуты или содержимое строки позже, вы должны использовать NSMutableAttributedString. Декларации очень похожи:

// Create a blank attributed string
let mutableAttrString1 = NSMutableAttributedString()

// Initialize with a string only
let mutableAttrString2 = NSMutableAttributedString(string: "Hello.")

// Initialize with a string and inline attribute(s)
let mutableAttrString3 = NSMutableAttributedString(string: "Hello.", attributes: [NSAttributedString.Key.myName: "A value"])

// Initialize with a string and separately declared attribute(s)
let myAttributes2 = [ NSAttributedString.Key.foregroundColor: UIColor.green ]
let mutableAttrString4 = NSMutableAttributedString(string: "Hello.", attributes: myAttributes2)

Изменение атрибутной строки

В качестве примера, давайте создадим приписанную строку в верхней части этого поста.

Сначала создайте NSMutableAttributedString с новым атрибутом шрифта.

let myAttribute = [ NSAttributedString.Key.font: UIFont(name: "Chalkduster", size: 18.0)! ]
let myString = NSMutableAttributedString(string: "Swift", attributes: myAttribute )

Если вы работаете вместе, UITextView атрибутивную строку UITextView (или UILabel) следующим образом:

textView.attributedText = myString

Вы не используете textView.text.

Вот результат:

Изображение 1693

Затем добавьте еще одну атрибутивную строку, для которой не установлены никакие атрибуты. (Обратите внимание, что хотя я и использовал let для объявления myString выше, я все же могу изменить его, потому что это NSMutableAttributedString. NSMutableAttributedString это кажется довольно непривлекательным, и я не удивлюсь, если это изменится в будущем. Оставьте мне комментарий, когда это случается.)

let attrString = NSAttributedString(string: " Attributed Strings")
myString.append(attrString)

Изображение 1694

Далее мы просто выберем слово "Strings", которое начинается с индекса 17 и имеет длину 7. Обратите внимание, что это NSRange а не Swift Range. (См. Этот ответ для получения дополнительной информации о диапазонах.) Метод addAttribute позволяет поместить имя ключа атрибута в первое место, значение атрибута во второе место и диапазон в третье место.

var myRange = NSRange(location: 17, length: 7) // range starting at location 17 with a lenth of 7: "Strings"
myString.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.red, range: myRange)

Изображение 1695

Наконец, позвольте добавить цвет фона. Для разнообразия, давайте использовать addAttributes метод (обратите внимание на s). Я мог бы добавить несколько атрибутов одновременно с этим методом, но я просто добавлю один снова.

myRange = NSRange(location: 3, length: 17)
let anotherAttribute = [ NSAttributedString.Key.backgroundColor: UIColor.yellow ]
myString.addAttributes(anotherAttribute, range: myRange)

Изображение 1696

Обратите внимание, что атрибуты перекрываются в некоторых местах. Добавление атрибута не перезаписывает атрибут, который уже существует.

связанные с

Дальнейшее чтение

  • 2
    Обратите внимание, что вы можете объединить несколько стилей для подчеркивания, например, NSUnderlineStyleAttributeName: NSUnderlineStyle.StyleSingle.rawValue | NSUnderlineStyle.PatternDot.rawValue
  • 3
    Вы не можете использовать appendAttributedString для NSAttributedString, это должно быть на NSMutableAttributedString, можете ли вы обновить свой ответ, чтобы отразить это?
Показать ещё 5 комментариев
100

Swift использует тот же NSMutableAttributedString, что и Obj-C. Вы создаете экземпляр, передавая в вычисленном значении строку:

var attributedString = NSMutableAttributedString(string:"\(calculatedCoffee)")

Теперь создайте атрибут g string (heh). Примечание. UIFont.systemFontOfSize(_) теперь является отказоустойчивым инициализатором, поэтому его необходимо развернуть, прежде чем вы сможете его использовать:

var attrs = [NSFontAttributeName : UIFont.systemFontOfSize(19.0)!]
var gString = NSMutableAttributedString(string:"g", attributes:attrs)

И затем добавьте его:

attributedString.appendAttributedString(gString)

Затем вы можете установить UILabel для отображения NSAttributedString следующим образом:

myLabel.attributedText = attributedString
  • 0
    //Part 1 Set Up The Lower Case g var coffeeText = NSMutableAttributedString(string:"\(calculateCoffee())") //Part 2 set the font attributes for the lower case g var coffeeTypeFaceAttributes = [NSFontAttributeName : UIFont.systemFontOfSize(18)] //Part 3 create the "g" character and give it the attributes var coffeeG = NSMutableAttributedString(string:"g", attributes:coffeeTypeFaceAttributes) Когда я устанавливаю свой UILabel.text = coffeeText, я получаю ошибку "NSMutableAttributedString не конвертируется в 'String'. Есть ли способ заставить UILabel принимать NSMutableAttributedString?
  • 8
    Когда у вас есть приписанная строка, вам нужно установить свойство attributeText метки вместо ее свойства text.
Показать ещё 3 комментария
18

Swift 4:

let attributes = [NSAttributedStringKey.font: UIFont(name: "HelveticaNeue-Bold", size: 17)!, 
                  NSAttributedStringKey.foregroundColor: UIColor.white]
  • 0
    он не компилируется. Type 'NSAttributedStringKey' (aka 'NSString') has no member 'font'
  • 0
    Я только что попробовал его в новейшем XCode (10 beta 6) и он компилируется, вы уверены, что используете Swift 4?
Показать ещё 3 комментария
16

Swift: xcode 6.1

    let font:UIFont? = UIFont(name: "Arial", size: 12.0)

    let attrString = NSAttributedString(
        string: titleData,
        attributes: NSDictionary(
            object: font!,
            forKey: NSFontAttributeName))
16

Версия Xcode 6:

let attriString = NSAttributedString(string:"attriString", attributes:
[NSForegroundColorAttributeName: UIColor.lightGrayColor(), 
            NSFontAttributeName: AttriFont])

Версия Xcode 9.3:

let attriString = NSAttributedString(string:"attriString", attributes:
[NSAttributedStringKey.foregroundColor: UIColor.lightGray, 
            NSAttributedStringKey.font: AttriFont])

Xcode 10, iOS 12, Swift 4:

let attriString = NSAttributedString(string:"attriString", attributes:
[NSAttributedString.Key.foregroundColor: UIColor.lightGray, 
            NSAttributedString.Key.font: AttriFont])
  • 0
    Идеальный код !!!
14

Я бы очень рекомендовал использовать библиотеку для атрибутных строк. Это делает его намного проще, если вы хотите, например, одну строку с четырьмя разными цветами и четырьмя разными шрифтами. Вот мой любимый. Он называется SwiftyAttributes

Если вы хотите создать строку с четырьмя разными цветами и разными шрифтами с помощью SwiftyAttributes:

let magenta = "Hello ".withAttributes([
    .textColor(.magenta),
    .font(.systemFont(ofSize: 15.0))
    ])
let cyan = "Sir ".withAttributes([
    .textColor(.cyan),
    .font(.boldSystemFont(ofSize: 15.0))
    ])
let green = "Lancelot".withAttributes([
    .textColor(.green),
    .font(.italicSystemFont(ofSize: 15.0))

    ])
let blue = "!".withAttributes([
    .textColor(.blue),
    .font(.preferredFont(forTextStyle: UIFontTextStyle.headline))

    ])
let finalString = magenta + cyan + green + blue

finalString будет отображаться как

Изображение 1697

9

Хорошо работает в бета-версии 6

let attrString = NSAttributedString(
    string: "title-title-title",
    attributes: NSDictionary(
       object: NSFont(name: "Arial", size: 12.0), 
       forKey: NSFontAttributeName))
7

Swift 2.0

Вот пример:

let newsString: NSMutableAttributedString = NSMutableAttributedString(string: "Tap here to read the latest Football News.")
newsString.addAttributes([NSUnderlineStyleAttributeName: NSUnderlineStyle.StyleDouble.rawValue], range: NSMakeRange(4, 4))
sampleLabel.attributedText = newsString.copy() as? NSAttributedString

ИЛИ

let stringAttributes = [
    NSFontAttributeName : UIFont(name: "Helvetica Neue", size: 17.0)!,
    NSUnderlineStyleAttributeName : 1,
    NSForegroundColorAttributeName : UIColor.orangeColor(),
    NSTextEffectAttributeName : NSTextEffectLetterpressStyle,
    NSStrokeWidthAttributeName : 2.0]
let atrributedString = NSAttributedString(string: "Sample String: Attributed", attributes: stringAttributes)
sampleLabel.attributedText = atrributedString
6

Лучший способ приблизиться к Attributed Strings на iOS - это использовать встроенный текстовый редактор Attributed Text в конструкторе интерфейса и избежать ненужного жесткого кодирования NSAtrributedStringKeys в ваших исходных файлах.

Позже вы можете динамически заменять placehoderls во время выполнения, используя это расширение:

extension NSAttributedString {
    func replacing(placeholder:String, with valueString:String) -> NSAttributedString {

        if let range = self.string.range(of:placeholder) {
            let nsRange = NSRange(range,in:valueString)
            let mutableText = NSMutableAttributedString(attributedString: self)
            mutableText.replaceCharacters(in: nsRange, with: valueString)
            return mutableText as NSAttributedString
        }
        return self
    }
}

Добавьте метку раскадровки с атрибутивным текстом, который выглядит следующим образом.

Изображение 1698

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

label.attributedText = initalAttributedString.replacing(placeholder: "<price>", with: newValue)

Обязательно сохраните в initalAttributedString исходное значение.

Вы можете лучше понять этот подход, прочитав эту статью: https://medium.com/mobile-appetite/text-attributes-on-ios-the-effortless-approach-ff086588173e

  • 0
    Это было очень полезно для моего случая, когда у меня была раскадровка, и я просто хотел добавить жирный шрифт к части строки в метке. Гораздо проще, чем настраивать все атрибуты вручную.
6

Я создал онлайн-инструмент, который решит вашу проблему! Вы можете написать свою строку и применить стили в графическом виде, и инструмент предоставит вам код target-c и swift для генерации этой строки.

Также с открытым исходным кодом, так что не стесняйтесь расширять его и отправлять PR.

Инструмент Трансформер

Github

Изображение 1699

  • 0
    Не работает для меня Он просто заключает все в скобки без применения какого-либо стиля.
4

Swift 4

let attributes = [NSAttributedStringKey.font : UIFont(name: CustomFont.NAME_REGULAR.rawValue, size: CustomFontSize.SURVEY_FORM_LABEL_SIZE.rawValue)!]

let attributedString : NSAttributedString = NSAttributedString(string: messageString, attributes: attributes)

Вам нужно удалить необработанное значение в swift 4

4
func decorateText(sub:String, des:String)->NSAttributedString{
    let textAttributesOne = [NSAttributedStringKey.foregroundColor: UIColor.darkText, NSAttributedStringKey.font: UIFont(name: "PTSans-Bold", size: 17.0)!]
    let textAttributesTwo = [NSAttributedStringKey.foregroundColor: UIColor.black, NSAttributedStringKey.font: UIFont(name: "PTSans-Regular", size: 14.0)!]

    let textPartOne = NSMutableAttributedString(string: sub, attributes: textAttributesOne)
    let textPartTwo = NSMutableAttributedString(string: des, attributes: textAttributesTwo)

    let textCombination = NSMutableAttributedString()
    textCombination.append(textPartOne)
    textCombination.append(textPartTwo)
    return textCombination
}

//Реализация

cell.lblFrom.attributedText = decorateText(sub: sender!, des: " - \(convertDateFormatShort3(myDateString: datetime!))")
4

Для меня выше решения не срабатывали при настройке определенного цвета или свойства.

Это работало:

let attributes = [
    NSFontAttributeName : UIFont(name: "Helvetica Neue", size: 12.0)!,
    NSUnderlineStyleAttributeName : 1,
    NSForegroundColorAttributeName : UIColor.darkGrayColor(),
    NSTextEffectAttributeName : NSTextEffectLetterpressStyle,
    NSStrokeWidthAttributeName : 3.0]

var atriString = NSAttributedString(string: "My Attributed String", attributes: attributes)
  • 0
    Но это не сработало в textview
3

Swift 2.1 - Xcode 7

let labelFont = UIFont(name: "HelveticaNeue-Bold", size: 18)
let attributes :[String:AnyObject] = [NSFontAttributeName : labelFont!]
let attrString = NSAttributedString(string:"foo", attributes: attributes)
myLabel.attributedText = attrString
  • 0
    Какие изменения были внесены между Swift 2.0 и 2.1?
2

Атрибуты могут устанавливаться непосредственно в swift 3...

    let attributes = NSAttributedString(string: "String", attributes: [NSFontAttributeName : UIFont(name: "AvenirNext-Medium", size: 30)!,
         NSForegroundColorAttributeName : UIColor .white,
         NSTextEffectAttributeName : NSTextEffectLetterpressStyle])

Затем используйте переменную в любом классе с атрибутами

2
extension UILabel{
    func setSubTextColor(pSubString : String, pColor : UIColor){    
        let attributedString: NSMutableAttributedString = self.attributedText != nil ? NSMutableAttributedString(attributedString: self.attributedText!) : NSMutableAttributedString(string: self.text!);

        let range = attributedString.mutableString.range(of: pSubString, options:NSString.CompareOptions.caseInsensitive)
        if range.location != NSNotFound {
            attributedString.addAttribute(NSForegroundColorAttributeName, value: pColor, range: range);
        }
        self.attributedText = attributedString
    }
}
  • 0
    cell. .setSubTextColor (pSubString: "Guest2", pColor: UIColor.red)
  • 1
    Добро пожаловать в ТАК. Пожалуйста, отформатируйте свой код и добавьте некоторые объяснения / контекст к вашему ответу. Смотрите: stackoverflow.com/help/how-to-answer
2
 let attrString = NSAttributedString (
            string: "title-title-title",
            attributes: [NSAttributedStringKey.foregroundColor: UIColor.black])
1

Swift 4.2

extension UILabel {

    func boldSubstring(_ substr: String) {
        guard substr.isEmpty == false,
            let text = attributedText,
            let range = text.string.range(of: substr, options: .caseInsensitive) else {
                return
        }
        let attr = NSMutableAttributedString(attributedString: text)
        let start = text.string.distance(from: text.string.startIndex, to: range.lowerBound)
        let length = text.string.distance(from: range.lowerBound, to: range.upperBound)
        attr.addAttributes([NSAttributedStringKey.font: UIFont.boldSystemFont(ofSize: self.font.pointSize)],
                           range: NSMakeRange(start, length))
        attributedText = attr
    }
}
  • 0
    Почему бы просто не range.count для длины?
1

Будет очень легко решить вашу проблему с созданной мной библиотекой. Он называется Atributika.

let calculatedCoffee: Int = 768
let g = Style("g").font(.boldSystemFont(ofSize: 12)).foregroundColor(.red)
let all = Style.font(.systemFont(ofSize: 12))

let str = "\(calculatedCoffee)<g>g</g>".style(tags: g)
    .styleAll(all)
    .attributedString

label.attributedText = str

Изображение 1700

Вы можете найти его здесь https://github.com/psharanda/Atributika

0

Swift 3.0//создаем приписанную строку

Определите атрибуты как

let attributes = [NSAttributedStringKey.font : UIFont.init(name: "Avenir-Medium", size: 13.0)]
0

Swift 4.x

let attr = [NSForegroundColorAttributeName:self.configuration.settingsColor, NSFontAttributeName: self.configuration.settingsFont]

let title = NSAttributedString(string: self.configuration.settingsTitle,
                               attributes: attr)
-4
extension String {
//MARK: Getting customized string
struct StringAttribute {
    var fontName = "HelveticaNeue-Bold"
    var fontSize: CGFloat?
    var initialIndexOftheText = 0
    var lastIndexOftheText: Int?
    var textColor: UIColor = .black
    var backGroundColor: UIColor = .clear
    var underLineStyle: NSUnderlineStyle = .styleNone
    var textShadow: TextShadow = TextShadow()

    var fontOfText: UIFont {
        if let font = UIFont(name: fontName, size: fontSize!) {
            return font
        } else {
            return UIFont(name: "HelveticaNeue-Bold", size: fontSize!)!
        }
    }

    struct TextShadow {
        var shadowBlurRadius = 0
        var shadowOffsetSize = CGSize(width: 0, height: 0)
        var shadowColor: UIColor = .clear
    }
}
func getFontifiedText(partOfTheStringNeedToConvert partTexts: [StringAttribute]) -> NSAttributedString {
    let fontChangedtext = NSMutableAttributedString(string: self, attributes: [NSFontAttributeName: UIFont(name: "HelveticaNeue-Bold", size: (partTexts.first?.fontSize)!)!])
    for eachPartText in partTexts {
        let lastIndex = eachPartText.lastIndexOftheText ?? self.count
        let attrs = [NSFontAttributeName : eachPartText.fontOfText, NSForegroundColorAttributeName: eachPartText.textColor, NSBackgroundColorAttributeName: eachPartText.backGroundColor, NSUnderlineStyleAttributeName: eachPartText.underLineStyle, NSShadowAttributeName: eachPartText.textShadow ] as [String : Any]
        let range = NSRange(location: eachPartText.initialIndexOftheText, length: lastIndex - eachPartText.initialIndexOftheText)
        fontChangedtext.addAttributes(attrs, range: range)
    }
    return fontChangedtext
}

}

//Используем как ниже

    let someAttributedText = "Some   Text".getFontifiedText(partOfTheStringNeedToConvert: <#T##[String.StringAttribute]#>)
  • 1
    Этот ответ расскажет вам все, что вам нужно знать, кроме как сделать атрибутивную строку в Swift.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню