Are there any analogues of [NSString stringWithFormat:] for NSAttributedString

前端 未结 4 1405
后悔当初
后悔当初 2020-12-09 05:14

Usually I build app interface in interface builder. Sometimes design requires to use attributed strings (fonts, colors and etc.). It\'s easy to configure if string is static

相关标签:
4条回答
  • 2020-12-09 05:49

    I was looking for good existing solution for this question, but no success.
    So I was able to implement it on my own.
    That's why I am self-answering the question to share the knowledge with community.

    Solution

    NSAttributedString+VPAttributedFormat category provides methods for building attributed string based on attributed format and arguments that should satisfy this format.
    The most suitable case of using this category is text controls with variable attributed text configured in interface builder.
    You need set correct string format to attributed text and configure necessary attributes.
    Then you need pass necessary arguments in code by using methods of this category.

    • Format syntax is the same as in [NSString stringWithFormat:] method;
    • Can be used in Objective C and Swift code;
    • Requires iOS 6.0 and later;
    • Integrated with CocoaPods;
    • Covered with unit tests.

    Usage

    1. Import framework header or module

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

    // Swift
    import VPAttributedFormat
    

    2. Set correct format and attributes for text control in interface builder
    usage

    3. Create IBOutlet and link it with text control

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

    // Swift
    @IBOutlet weak var textLabel: UILabel!
    

    4. Populate format with necessary arguments

    // 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. See result
    result

    Examples

    VPAttributedFormatExample is an example project. It provides Basic and Pro format examples.
    example

    0 讨论(0)
  • 2020-12-09 05:56

    Here's a category I wrote to add the method to NSAttributedString. You'll have to pass in NULL as the last argument to the function however, otherwise it will crash to the va_list restrictions on detecting size. [attributedString 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
    
    0 讨论(0)
  • 2020-12-09 06:02

    Compatible with 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)
        }
    }
    

    Usage:

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

    Result:

    0 讨论(0)
  • 2020-12-09 06:02

    Here is a Swift 4 extension based on TheJeff's answer (corrected for multiple substitutions). It is restricted to substituting placeholders with NSAttributedString's:

    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)
        }
    }
    
    0 讨论(0)
提交回复
热议问题