Существуют ли какие-либо аналоги [NSString stringWithFormat:] для NSAttributedString

Обычно я создаю интерфейс приложения в построителе интерфейса. Иногда дизайн требует использования атрибутированных строк (шрифтов, цветов и т.д.). Легко настроить, является ли строка статичной.
Но если строка является динамической (формат с аргументами), тогда нет способов настроить атрибуты в построителе интерфейса. Это требует, чтобы написать много кода.
Я ищу некоторые аналоги [NSString stringWithFormat:] для NSAttributedString. Поэтому я смогу установить строковый формат и необходимые атрибуты в построителе интерфейса, а затем предоставить необходимые аргументы в коде.

Например:
Предположим, что мне нужна строка отображения с таким форматом: "% d + % d= % d" (все цифры выделены жирным шрифтом). < ш > Я хочу настроить этот формат в построителе интерфейса. В коде я хочу предоставить аргументы: 1, 1, 2. Приложение должно показать " 1 + 1= 2".

Ответ 1

Я искал хорошее существующее решение для этого вопроса, но не добился успеха.
Поэтому я смог реализовать это самостоятельно.
Вот почему я сам отвечаю на вопрос об обмене знаниями с сообществом.

Решение

категория NSAttributedString + VPAttributedFormat предоставляет методы построения атрибутивной строки на основе атрибутного формата и аргументов, которые должны удовлетворять этому формату.
Наиболее подходящим случаем использования этой категории являются текстовые элементы управления с переменным атрибутом текста, сконфигурированным в построителе интерфейса.
Вам необходимо установить правильный формат строки для атрибута текста и настроить необходимые атрибуты.
Затем вам необходимо передать необходимые аргументы в коде, используя методы этой категории.

  • Формат синтаксиса такой же, как в методе [NSString stringWithFormat:];
  • Может использоваться в коде Objective C и Swift;
  • Требуется iOS 6.0 и более поздние версии;
  • Интегрировано с CocoaPods;
  • В комплекте с модульными тестами.

Использование

1. Импортировать заголовок или модуль структуры

// Objective C
// By header
#import <VPAttributedFormat/VPAttributedFormat.h>

// By module
@import VPAttributedFormat;

// Swift
import VPAttributedFormat

2. Установите правильный формат и атрибуты для управления текстом в построителе интерфейсов
usage

3. Создайте IBOutlet и привяжите его с помощью текстового управления

// Objective C
@property (nonatomic, weak) IBOutlet UILabel *textLabel;

// Swift
@IBOutlet weak var textLabel: UILabel!

4. Задать формат с необходимыми аргументами

// Objective C
NSString *hot = @"Hot";
NSString *cold = @"Cold";

self.textLabel.attributedText = [NSAttributedString vp_attributedStringWithAttributedFormat:self.textLabel.attributedText,
                                 hot,
                                 cold];

// Swift
let hot = "Hot"
let cold = "Cold"
var arguments: [CVarArgType] = [hot, cold]
textLabel.attributedText = withVaList(arguments) { pointer in
    NSAttributedString.vp_attributedStringWithAttributedFormat(textLabel.attributedText, arguments: pointer)
}

5. См. Результат
result

Примеры

VPAttributedFormatExample - пример проекта. Он предоставляет примеры форматов Basic и Pro.
example

Ответ 2

Вот категория, которую я написал, чтобы добавить метод в NSAttributedString. Вы должны будете передать NULL в качестве последнего аргумента функции, однако в противном случае он будет сбой к ограничениям va_list для определения размера. [attribitedString stringWithFormat: attrFormat, attrArg1, attrArg2, NULL];

@implementation NSAttributedString(stringWithFormat)

+(NSAttributedString*)stringWithFormat:(NSAttributedString*)format, ...{
    va_list args;
    va_start(args, format);

    NSMutableAttributedString *mutableAttributedString = (NSMutableAttributedString*)[format mutableCopy];
    NSString *mutableString = [mutableAttributedString string];

    while (true) {
        NSAttributedString *arg = va_arg(args, NSAttributedString*);
        if (!arg) {
            break;
        }
        NSRange rangeOfStringToBeReplaced = [mutableString rangeOfString:@"%@"];
        [mutableAttributedString replaceCharactersInRange:rangeOfStringToBeReplaced withAttributedString:arg];
    }

    va_end(args);

    return mutableAttributedString;
}
@end

Ответ 3

Вот расширение Swift 4, основанное на ответе TheJeff (исправлено для нескольких подстановок). Он ограничен заменой заполнителей на NSAttributedString:

public extension NSAttributedString {
    convenience init(format: NSAttributedString, args: NSAttributedString...) {
        let mutableNSAttributedString = NSMutableAttributedString(attributedString: format)

        var nsRange = NSString(string: mutableNSAttributedString.string).range(of: "%@")
        var param = 0
        while nsRange.location != NSNotFound {
            guard args.count > 0, param < args.count else {
                fatalError("Not enough arguments provided for \(format)")
            }

            mutableNSAttributedString.replaceCharacters(in: nsRange, with: args[param])
            param += 1
            nsRange = NSString(string: mutableNSAttributedString.string).range(of: "%@")
        }

        self.init(attributedString: mutableNSAttributedString)
    }
}

Ответ 4

Совместим с Swift 4.2

public extension NSAttributedString {
    convenience init(format: NSAttributedString, args: NSAttributedString...) {
        let mutableNSAttributedString = NSMutableAttributedString(attributedString: format)

        args.forEach { (attributedString) in
            let range = NSString(string: mutableNSAttributedString.string).range(of: "%@")
            mutableNSAttributedString.replaceCharacters(in: range, with: attributedString)
        }
        self.init(attributedString: mutableNSAttributedString)
    }
}

Использование:

let content = NSAttributedString(string: "The quick brown %@ jumps over the lazy %@")
let fox = NSAttributedString(string: "fox", attributes: [.font: Fonts.CalibreReact.boldItalic])
let dog = NSAttributedString(string: "dog", attributes: [.font: Fonts.CalibreReact.lightItalic])
attributedLabel.attributedText = NSAttributedString(format: content, args: fox, dog)

Результат:

enter image description here