How to make NSMutableAttributedString responsive with dynamic type text from settings app

6.9k Views Asked by At
let dictTitleColor = [NSAttributedStringKey.foregroundColor: UIColor.LTColor()]
let titleAttributedString = NSMutableAttributedString(string: title, attributes: dictTitleColor)
alert.setValue(titleAttributedString, forKey: "attributedTitle")

When I Increase the font size of the device the title string dont increase i have set this string in alertview controller ? So How to make This Responsive to font size Change ?

2

There are 2 best solutions below

8
On
let dictTitleColor = [NSAttributedStringKey.foregroundColor : UIColor.green,
                      NSAttributedStringKey.font : UIFont.preferredFont(forTextStyle: .headline)]
let titleAttributedString = NSMutableAttributedString(string: title, attributes: dictTitleColor)
alert.setValue(titleAttributedString, forKey: "attributedTitle")

NOTE: This will fail if the popup is presented and then user changed the font size in the accessibility settings. For this case you might need to listen to the UIContentSizeCategory.didChangeNotification and update the font size there.

e.g.

NotificationCenter.default.addObserver(self, selector: #selector(preferredContentSizeChanged(_:)), name: UIContentSizeCategory.didChangeNotification, object: nil)

The method

@objc func preferredContentSizeChanged(_ notification: Notification) {
  let dictTitleColor = [NSAttributedStringKey.foregroundColor : UIColor.green,
                        NSAttributedStringKey.font : UIFont.preferredFont(forTextStyle: .headline)]
  let titleAttributedString = NSMutableAttributedString(string: title, attributes: dictTitleColor)
  alert.setValue(titleAttributedString, forKey: "attributedTitle")
}
0
On

To adapt dynamic font size and enable accessibility for attributed text you can use the following function.

static func convertHtml(string: String?) -> NSAttributedString? {
    
    guard let string = string else {return nil}
    
    guard let data = string.data(using: .utf8) else {
        return nil
    }
    
    do {
        let attrStr = try NSAttributedString(data: data,
                                      options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue],
                                      documentAttributes: nil)
        let range = NSRange(location: 0, length: attrStr.length)
        let str = NSMutableAttributedString(attributedString: attrStr)
        
        str.enumerateAttribute(NSAttributedString.Key.font, in: NSMakeRange(0, str.length), options: .longestEffectiveRangeNotRequired) {
            (value, range, stop) in
            if let font = value as? UIFont {
                
                let userFont =  UIFontDescriptor.preferredFontDescriptor(withTextStyle: .title2)
                let pointSize = userFont.withSize(font.pointSize)
                let customFont = UIFont.systemFont(ofSize: pointSize.pointSize)
                let dynamicText = UIFontMetrics.default.scaledFont(for: customFont)
                str.addAttribute(NSAttributedString.Key.font,
                                         value: dynamicText,
                                         range: range)
            }
        }

        str.addAttribute(NSAttributedString.Key.underlineStyle, value: 0, range: range)
        
        return NSAttributedString(attributedString: str.attributedSubstring(from: range))
    } catch {}
    return nil
    
}

Then you can you this on ur textview.

let htmToStringText = convertHtml(string: html))
            
  self.bodyTextView.isEditable = false
  self.bodyTextView.isAccessibilityElement = true
  self.bodyTextView.adjustsFontForContentSizeCategory = true
  self.bodyTextView.attributedText = htmToStringText
  self.bodyTextView.accessibilityAttributedLabel = htmToStringText