Search code examples
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

  • change the selected text to bold or italic
  • change the selected text which is bold to italic or vice versa

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)