Search code examples
swiftstringappendnstextviewnsmutableattributedstring

NSMutableAttributedString for adding subscript (superscript) for NSTextView from String


Does there exist a way to append NSMutableAttributedString within normal String?

I would like to add text to NSTextView. This particular text (String) has references from Double() variables and I would like to add some upper and bottom indexes (subscript and superscript).

It is math software for structural engineers and output is big text with multiple lines and I would like to know, if there exist more simple or direct way how to add this indexes (A = 5 m2 (meters squared)).

I can't forced numerical subscripted font characters (⁰ ¹ ² ³ ⁴ ⁵ ⁶ ⁷ ⁸ ⁹ ₀ ₁ ₂ ₃ ₄ ₅ ₆ ₇ ₈ ₉), because in certain cases is necessary to have even letters or symbols sub-/superscripted.

I would like to know if there exist way how to create such attributed string and add to container of text.

PS: I checked already these answers (Swift 3.0 convert Double() to NSMutableAttributedString) but I have troubles to use it within String with references like in this example:

var x = Double()
var y = Double()
var z = Double()
x = 10
y = 5

z = x * y  // = 50
var str = String()
str = "Random text for example porpoises:\n\nHere comes calculation part\n\nA1 = \(z) m2"

print(str)
//Random text for example porpoises:
//
//Here comes calculation part
//
//A1 = 50 m2

//"1" in "A1" should be subscripted (A_1)
//"2" in "m2" should be superscripted (m^2)

I would like to know how I can add those sub- and superscripts and put this Attributed String to NSTextView


Solution

  • I would suggest using a standard NSAttributedString and NSBaselineOffsetAttributeName. Take a look at the example I just put together:

    override func viewDidLoad() {
        super.viewDidLoad()
    
        let label = NSTextView(frame: CGRect(x: 20, y: 20, width: 100, height: 30))
        let str = "A1 = 50 m2"
    
        let aString = NSMutableAttributedString(string: str)
    
        let myFont = NSFont(name: label.font!.fontName, size: 10.0)
        let subscriptAttributes: [String : Any] = [ NSBaselineOffsetAttributeName: -5, NSFontAttributeName:  myFont! ]
        let superscriptAttributes: [String : Any] = [ NSBaselineOffsetAttributeName: 5, NSFontAttributeName:  myFont! ]
    
        aString.addAttributes(subscriptAttributes, range: NSRange(location: 1, length: 1))
        aString.addAttributes(superscriptAttributes, range: NSRange(location: 9, length: 1))
    
        // Kerning adds a little spacing between all the characters.
        aString.addAttribute(NSKernAttributeName, value: 1.5, range: NSRange(location: 0, length: 2))
        aString.addAttribute(NSKernAttributeName, value: 1.5, range: NSRange(location: 8, length: 2))
    
    
        label.textStorage?.append(aString)
    
        view.addSubview(label)
    }
    

    Here's the result:

    enter image description here