Как создать привязанную строку с помощью Swift?

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

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

var coffeeAmount: String = calculatedCoffee + attributedText

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

Ответ 1

enter image description here

Этот ответ был обновлен для 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

Text Color

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

Background Color

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

Font

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

enter image description here

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

enter image description here

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.

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

enter image description here

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

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

enter image description here

Далее мы просто выберем слово "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)

enter image description here

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

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

enter image description here

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

связанные с

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

Ответ 2

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

Ответ 3

Swift 4:

let attributes = [NSAttributedStringKey.font: UIFont(name: "HelveticaNeue-Bold", size: 17)!, 
                  NSAttributedStringKey.foregroundColor: UIColor.white]

Ответ 4

Версия 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])

Ответ 5

Swift: xcode 6.1

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

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

Ответ 6

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

Показывает как изображение

Ответ 7

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

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

Ответ 8

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

Ответ 9

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

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

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

Github

enter image description here

Ответ 10

Лучший способ приблизиться к 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
    }
}

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

enter image description here

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

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

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

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

Ответ 11

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

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

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)

Ответ 12

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

Ответ 13

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

Ответ 14

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

Ответ 15

 let attrString = NSAttributedString (
            string: "title-title-title",
            attributes: [NSAttributedStringKey.foregroundColor: UIColor.black])

Ответ 16

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

Ответ 17

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

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

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

Ответ 18

Будет очень легко решить вашу проблему с созданной мной библиотекой. Он называется 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

768g

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

Ответ 19

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

Ответ 20

Swift 4.x

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

let title = NSAttributedString(string: self.configuration.settingsTitle,
                               attributes: attr)

Ответ 21

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

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

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

Ответ 22

Пожалуйста, рассмотрите возможность использования Prestyler

import Prestyler
...
Prestyle.defineRule("$", UIColor.red)
label.attributedText = "\(calculatedCoffee) $g$".prestyled()

Ответ 23

Swift 5 и выше

   let attributedString = NSAttributedString(string:"targetString",
                                   attributes:[NSAttributedString.Key.foregroundColor: UIColor.lightGray,
                                               NSAttributedString.Key.font: UIFont(name: "Arial", size: 18.0) as Any])

Ответ 24

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

''' Swift
let defaultGenreText = NSAttributedString(string: "Select Genre - Required")
let redGenreText = defaultGenreText.applying(attributes: [NSAttributedString.Key.foregroundColor : UIColor.red], toRangesMatching: "Required")
''

Если у вас есть несколько мест, где это будет применяться, и вы хотите, чтобы это происходило только в определенных случаях, этот метод не сработает.

Вы можете сделать это за один шаг, просто легче читать, когда разделены.

Ответ 25

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