-
-
Save hvsw/d6027be8dd73f4dc71bbfb374ba8b2f8 to your computer and use it in GitHub Desktop.
Adds a simple way to register a view for automatic dynamic type updating by setting respondsToDynamicTypeChanges = true. Really only useful on iOS < 10
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import ObjectiveC | |
// MARK: - DynamicTypeResponsive | |
protocol DynamicTypeResponsive { | |
var respondsToDynamicTypeChanges: Bool { get set } | |
} | |
extension UILabel: DynamicTypeResponsive { | |
var respondsToDynamicTypeChanges: Bool { | |
set { | |
if #available(iOS 10.0, *) { | |
self.adjustsFontForContentSizeCategory = newValue | |
} else { | |
let handler: NotificationHandler = { [weak self] _ in | |
if let strongSelf = self, | |
let style = strongSelf.font.textStyle { | |
strongSelf.font = .preferredFont(forTextStyle: style) | |
strongSelf.invalidateIntrinsicContentSize() | |
} | |
} | |
self.setContentSizeDidChangeHandler(newValue ? handler : nil) | |
} | |
} | |
get { | |
if #available(iOS 10.0, *) { | |
return self.adjustsFontForContentSizeCategory | |
} else { | |
return self.contentSizeNotificationObserver != nil | |
} | |
} | |
} | |
} | |
extension UITextView: DynamicTypeResponsive { | |
var respondsToDynamicTypeChanges: Bool { | |
set { | |
if #available(iOS 10.0, *) { | |
self.adjustsFontForContentSizeCategory = newValue | |
} else { | |
let handler: NotificationHandler = { [weak self] _ in | |
if let strongSelf = self, | |
let style = strongSelf.font?.textStyle { | |
strongSelf.font = .preferredFont(forTextStyle: style) | |
strongSelf.invalidateIntrinsicContentSize() | |
} | |
} | |
self.setContentSizeDidChangeHandler(newValue ? handler : nil) | |
} | |
} | |
get { | |
if #available(iOS 10.0, *) { | |
return self.adjustsFontForContentSizeCategory | |
} else { | |
return self.contentSizeNotificationObserver != nil | |
} | |
} | |
} | |
} | |
extension UITextField: DynamicTypeResponsive { | |
var respondsToDynamicTypeChanges: Bool { | |
set { | |
if #available(iOS 10.0, *) { | |
self.adjustsFontForContentSizeCategory = newValue | |
} else { | |
let handler: NotificationHandler = { [weak self] _ in | |
if let strongSelf = self, | |
let style = strongSelf.font?.textStyle { | |
strongSelf.font = .preferredFont(forTextStyle: style) | |
strongSelf.invalidateIntrinsicContentSize() | |
} | |
} | |
self.setContentSizeDidChangeHandler(newValue ? handler : nil) | |
} | |
} | |
get { | |
if #available(iOS 10.0, *) { | |
return self.adjustsFontForContentSizeCategory | |
} else { | |
return self.contentSizeNotificationObserver != nil | |
} | |
} | |
} | |
} | |
extension UIButton: DynamicTypeResponsive { | |
var respondsToDynamicTypeChanges: Bool { | |
set { | |
self.titleLabel?.respondsToDynamicTypeChanges = newValue | |
} | |
get { | |
return self.titleLabel?.respondsToDynamicTypeChanges ?? false | |
} | |
} | |
} | |
// MARK: - Notification Handling for UIContentSizeCategoryDidChange | |
typealias NotificationHandler = (Notification) -> Void | |
var NotificationObserverKey: String = "NotificationObserverKey" | |
protocol DynamicTypeAdjusting: class { | |
func setContentSizeDidChangeHandler(_ handler: NotificationHandler?) | |
var contentSizeNotificationObserver: NSObjectProtocol? { get set } | |
} | |
extension DynamicTypeAdjusting where Self: NSObject { | |
func setContentSizeDidChangeHandler(_ handler: NotificationHandler?) { | |
if let handler = handler { | |
let observer = NotificationCenter.default.addObserver(forName: .UIContentSizeCategoryDidChange, | |
object: nil, | |
queue: .main, | |
using: handler) | |
self.contentSizeNotificationObserver = observer | |
} else { | |
self.contentSizeNotificationObserver = nil | |
} | |
} | |
var contentSizeNotificationObserver: NSObjectProtocol? { | |
set { | |
withUnsafePointer(to: &NotificationObserverKey) { (p) -> Void in | |
objc_setAssociatedObject(self, p, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) | |
} | |
} | |
get { | |
return withUnsafePointer(to: &NotificationObserverKey) { (p) -> NSObjectProtocol? in | |
return objc_getAssociatedObject(self, p) as? NSObjectProtocol | |
} | |
} | |
} | |
} | |
extension UILabel: DynamicTypeAdjusting { } | |
extension UITextField: DynamicTypeAdjusting { } | |
extension UITextView: DynamicTypeAdjusting { } | |
// MARK: - UIFont Helpers | |
extension UIFont { | |
var textStyle: UIFontTextStyle? { | |
return self.fontDescriptor.textStyle | |
} | |
} | |
extension UIFontDescriptor.AttributeName { | |
static let nsctFontUIUsage = UIFontDescriptor.AttributeName(rawValue: "NSCTFontUIUsageAttribute") | |
} | |
extension UIFontDescriptor { | |
var textStyle: UIFontTextStyle? { | |
guard let fontAttribute = fontAttributes[.nsctFontUIUsage] as? String else { | |
return nil | |
} | |
switch fontAttribute { | |
case "UICTFontTextStyleHeadline", "AppleSystemUIHeadline": | |
return .headline | |
case "UICTFontTextStyleSubhead": | |
return .subheadline | |
case "UICTFontTextStyleBody": | |
return .body | |
case "UICTFontTextStyleFootnote": | |
return .footnote | |
case "UICTFontTextStyleCaption1": | |
return .caption1 | |
case "UICTFontTextStyleCaption2": | |
return .caption2 | |
case "UICTFontTextStyleCallout": | |
return .callout | |
case "UICTFontTextStyleTitle1": | |
return .title1 | |
case "UICTFontTextStyleTitle2": | |
return .title2 | |
case "UICTFontTextStyleTitle3": | |
return .title3 | |
default: | |
fatalError("Style '\(fontAttribute)' not handled!") // Will need to support new styles added in iOS 11 | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment