iosswiftuitextviewtextkitnstextstorage

How to toggle Bold and Italic of UIFont


I'm trying to apply Bold and Italic to selected text in UITextView using textKit in swift.

This is the code:

let isBold = false

if !isActive(modification: .swapBoldWithItalic) || isBold{
    storage.setAttributes(attributes, range: range)
} else {
    let currentFont = attributes![.font] as? UIFont
    
    let fontDescriptor = currentFont?.fontDescriptor
    
    var changedFontDescriptor: UIFontDescriptor?
    
    if fontDescriptor!.symbolicTraits.contains(.traitItalic) {
        changedFontDescriptor = fontDescriptor?.withSymbolicTraits(fontDescriptor!.symbolicTraits.union(.traitItalic))
        
    } else {
        changedFontDescriptor = fontDescriptor?.withSymbolicTraits(fontDescriptor!.symbolicTraits.union(.traitBold))
        
    }
    
    
    var updatedFont: UIFont? = nil
    if let changedFontDescriptor = changedFontDescriptor {
        updatedFont = UIFont(descriptor: changedFontDescriptor, size: (currentFont?.pointSize)!)
        
    }
    let dict = [
        NSAttributedString.Key.font: updatedFont,
        NSAttributedString.Key.foregroundColor: UIColor.red
    ]
    
    storage.setAttributes(dict, range: range)
}

What I'm trying to achieve is

What is happening now is when i select text and change it to bold it changes to bold, but when i try to change another text to Italic also it changes to bold and I'm still not able to swap from bold to italic.


Solution

  • I suspect you wanna toggle bold and italic by different buttons. I've made an extension which will be easy for you to use:

    extension UIFont {
        func byTogglingSymbolicTraits(_ symbolicTraits: UIFontDescriptor.SymbolicTraits) -> UIFont {
            UIFont(
                descriptor: fontDescriptor.byTogglingSymbolicTraits(symbolicTraits),
                size: pointSize
            )
        }
    }
    
    extension UIFontDescriptor {
        func byTogglingSymbolicTraits(_ traints: UIFontDescriptor.SymbolicTraits) -> UIFontDescriptor {
            if symbolicTraits.contains(traints) {
                return withSymbolicTraits(symbolicTraits.subtracting(traints))!
            } else {
                return withSymbolicTraits(symbolicTraits.union(traints))!
            }
        }
    }
    

    Usage:

    font = font.byTogglingSymbolicTraits(.traitBold)
    // or
    font = font.byTogglingSymbolicTraits(.traitItalic)