我尝试了两种方式:
方法一:
label.font = UIFont.preferredFont(forTextStyle: UIFontTextStyle.body)
label.adjustsFontForContentSizeCategory = true
这工作正常,即使在设置中更改了首选文本大小,文本大小也会自动更改,甚至在我返回应用程序之前也是如此。 但是它只适用于系统字体(San Francisco)。
方法二:
要使用自定义字体,我向 UIFontDescriptor
添加了一个扩展:
//from this answer http://stackoverflow.com/a/35467158/2907715
extension UIFontDescriptor {
private struct SubStruct {
static var preferredFontName: String = "Avenir-medium"
}
static let fontSizeTable : NSDictionary = [
UIFontTextStyle.headline: [
UIContentSizeCategory.accessibilityExtraExtraExtraLarge: 23,
UIContentSizeCategory.accessibilityExtraExtraLarge: 23,
UIContentSizeCategory.accessibilityExtraLarge: 23,
UIContentSizeCategory.accessibilityLarge: 23,
UIContentSizeCategory.accessibilityMedium: 23,
UIContentSizeCategory.extraExtraExtraLarge: 23,
UIContentSizeCategory.extraExtraLarge: 21,
UIContentSizeCategory.extraLarge: 19,
UIContentSizeCategory.large: 17,
UIContentSizeCategory.medium: 16,
UIContentSizeCategory.small: 15,
UIContentSizeCategory.extraSmall: 14
],
UIFontTextStyle.subheadline: [
UIContentSizeCategory.accessibilityExtraExtraExtraLarge: 21,
UIContentSizeCategory.accessibilityExtraExtraLarge: 21,
UIContentSizeCategory.accessibilityExtraLarge: 21,
UIContentSizeCategory.accessibilityLarge: 21,
UIContentSizeCategory.accessibilityMedium: 21,
UIContentSizeCategory.extraExtraExtraLarge: 21,
UIContentSizeCategory.extraExtraLarge: 19,
UIContentSizeCategory.extraLarge: 17,
UIContentSizeCategory.large: 15,
UIContentSizeCategory.medium: 14,
UIContentSizeCategory.small: 13,
UIContentSizeCategory.extraSmall: 12
],
UIFontTextStyle.body: [
UIContentSizeCategory.accessibilityExtraExtraExtraLarge: 53,
UIContentSizeCategory.accessibilityExtraExtraLarge: 47,
UIContentSizeCategory.accessibilityExtraLarge: 40,
UIContentSizeCategory.accessibilityLarge: 33,
UIContentSizeCategory.accessibilityMedium: 28,
UIContentSizeCategory.extraExtraExtraLarge: 23,
UIContentSizeCategory.extraExtraLarge: 21,
UIContentSizeCategory.extraLarge: 19,
UIContentSizeCategory.large: 17,
UIContentSizeCategory.medium: 16,
UIContentSizeCategory.small: 15,
UIContentSizeCategory.extraSmall: 14
],
UIFontTextStyle.caption1: [
UIContentSizeCategory.accessibilityExtraExtraExtraLarge: 18,
UIContentSizeCategory.accessibilityExtraExtraLarge: 18,
UIContentSizeCategory.accessibilityExtraLarge: 18,
UIContentSizeCategory.accessibilityLarge: 18,
UIContentSizeCategory.accessibilityMedium: 18,
UIContentSizeCategory.extraExtraExtraLarge: 18,
UIContentSizeCategory.extraExtraLarge: 16,
UIContentSizeCategory.extraLarge: 14,
UIContentSizeCategory.large: 12,
UIContentSizeCategory.medium: 11,
UIContentSizeCategory.small: 11,
UIContentSizeCategory.extraSmall: 11
],
UIFontTextStyle.caption2: [
UIContentSizeCategory.accessibilityExtraExtraExtraLarge: 17,
UIContentSizeCategory.accessibilityExtraExtraLarge: 17,
UIContentSizeCategory.accessibilityExtraLarge: 17,
UIContentSizeCategory.accessibilityLarge: 17,
UIContentSizeCategory.accessibilityMedium: 17,
UIContentSizeCategory.extraExtraExtraLarge: 17,
UIContentSizeCategory.extraExtraLarge: 15,
UIContentSizeCategory.extraLarge: 13,
UIContentSizeCategory.large: 11,
UIContentSizeCategory.medium: 11,
UIContentSizeCategory.small: 11,
UIContentSizeCategory.extraSmall: 11
],
UIFontTextStyle.footnote: [
UIContentSizeCategory.accessibilityExtraExtraExtraLarge: 19,
UIContentSizeCategory.accessibilityExtraExtraLarge: 19,
UIContentSizeCategory.accessibilityExtraLarge: 19,
UIContentSizeCategory.accessibilityLarge: 19,
UIContentSizeCategory.accessibilityMedium: 19,
UIContentSizeCategory.extraExtraExtraLarge: 19,
UIContentSizeCategory.extraExtraLarge: 17,
UIContentSizeCategory.extraLarge: 15,
UIContentSizeCategory.large: 13,
UIContentSizeCategory.medium: 12,
UIContentSizeCategory.small: 12,
UIContentSizeCategory.extraSmall: 12
],
]
final class func preferredDescriptor(textStyle: String) -> UIFontDescriptor {
let contentSize = UIApplication.shared.preferredContentSizeCategory
let style = fontSizeTable[textStyle] as! NSDictionary
return UIFontDescriptor(name: SubStruct.preferredFontName, size: CGFloat((style[contentSize] as! NSNumber).floatValue))
}
}
在 viewDidLoad()
中:
label.font = UIFont(descriptor: UIFontDescriptor.preferredDescriptor(textStyle: UIFontTextStyle.body.rawValue), size: 0)
NotificationCenter.default.addObserver(self, selector:#selector(self.userChangedTextSize(notification:)), name: NSNotification.Name.UIContentSizeCategoryDidChange, object: nil)
这是 userChangedTextSize
函数:
func userChangedTextSize(notification: NSNotification) {
label.font = UIFont(descriptor: UIFontDescriptor.preferredDescriptor(textStyle: UIFontTextStyle.body.rawValue), size: 0)
}
问题此方法的文本大小在用户返回应用程序之前不会更改,然后用户会看到旧文本大小更改为新大小,这不理想。
我能否两全其美:一种大小可在后台自动更改的自定义字体?
最佳答案
The problem with this method is that the text size won't change until the user goes back to the app, and then the user would see the old text size change to the new size, which is not ideal.
我同意您的想法,即这可能是一个更好的用户体验,但我猜您有点想多了。
如果您查看系统提供的应用程序(例如联系人),您会清楚地看到直到用户返回应用程序才完成刷新。
顺便说一句,你可以为 Swift 3 重构你的代码:
extension UIFontDescriptor {
private struct SubStruct {
static var preferredFontName: String = "Avenir-medium"
}
static let fontSizeTable: [UIFontTextStyle: [UIContentSizeCategory: CGFloat]] = [
.headline: [
.accessibilityExtraExtraExtraLarge: 23,
.accessibilityExtraExtraLarge: 23,
.accessibilityExtraLarge: 23,
.accessibilityLarge: 23,
.accessibilityMedium: 23,
.extraExtraExtraLarge: 23,
.extraExtraLarge: 21,
.extraLarge: 19,
.large: 17,
.medium: 16,
.small: 15,
.extraSmall: 14
],
.subheadline: [
.accessibilityExtraExtraExtraLarge: 21,
.accessibilityExtraExtraLarge: 21,
.accessibilityExtraLarge: 21,
.accessibilityLarge: 21,
.accessibilityMedium: 21,
.extraExtraExtraLarge: 21,
.extraExtraLarge: 19,
.extraLarge: 17,
.large: 15,
.medium: 14,
.small: 13,
.extraSmall: 12
],
.body: [
.accessibilityExtraExtraExtraLarge: 53,
.accessibilityExtraExtraLarge: 47,
.accessibilityExtraLarge: 40,
.accessibilityLarge: 33,
.accessibilityMedium: 28,
.extraExtraExtraLarge: 23,
.extraExtraLarge: 21,
.extraLarge: 19,
.large: 17,
.medium: 16,
.small: 15,
.extraSmall: 14
],
.caption1: [
.accessibilityExtraExtraExtraLarge: 18,
.accessibilityExtraExtraLarge: 18,
.accessibilityExtraLarge: 18,
.accessibilityLarge: 18,
.accessibilityMedium: 18,
.extraExtraExtraLarge: 18,
.extraExtraLarge: 16,
.extraLarge: 14,
.large: 12,
.medium: 11,
.small: 11,
.extraSmall: 11
],
.caption2: [
.accessibilityExtraExtraExtraLarge: 17,
.accessibilityExtraExtraLarge: 17,
.accessibilityExtraLarge: 17,
.accessibilityLarge: 17,
.accessibilityMedium: 17,
.extraExtraExtraLarge: 17,
.extraExtraLarge: 15,
.extraLarge: 13,
.large: 11,
.medium: 11,
.small: 11,
.extraSmall: 11
],
.footnote: [
.accessibilityExtraExtraExtraLarge: 19,
.accessibilityExtraExtraLarge: 19,
.accessibilityExtraLarge: 19,
.accessibilityLarge: 19,
.accessibilityMedium: 19,
.extraExtraExtraLarge: 19,
.extraExtraLarge: 17,
.extraLarge: 15,
.large: 13,
.medium: 12,
.small: 12,
.extraSmall: 12
]
]
final class func preferredDescriptor(textStyle: UIFontTextStyle) -> UIFontDescriptor {
let contentSize = UIApplication.shared.preferredContentSizeCategory
let style = fontSizeTable[textStyle]!
return UIFontDescriptor(name: SubStruct.preferredFontName, size: style[contentSize]!)
}
}
无需转换为 NSDictionary
或 NSNumber
并间接获取 floatValue
。
这样您的调用站点就可以使用以下更易读的代码:
func userChangedTextSize(notification: NSNotification) {
label.font = UIFont(descriptor: .preferredDescriptor(textStyle: .body), size: 0)
}
编辑:因为我现在正在做同样的事情,所以我将上面的内容(在如此常见的解决方案上)改进为更简单的方法。
import UIKIt
extension UIFont {
private struct CustomFont {
static var fontFamily = "Avenir"
}
/// Returns a bold version of `self`
public var bolded: UIFont {
return fontDescriptor.withSymbolicTraits(.traitBold)
.map { UIFont(descriptor: $0, size: 0) } ?? self
}
/// Returns an italic version of `self`
public var italicized: UIFont {
return fontDescriptor.withSymbolicTraits(.traitItalic)
.map { UIFont(descriptor: $0, size: 0) } ?? self
}
/// Returns a scaled version of `self`
func scaled(scaleFactor: CGFloat) -> UIFont {
let newDescriptor = fontDescriptor.withSize(fontDescriptor.pointSize * scaleFactor)
return UIFont(descriptor: newDescriptor, size: 0)
}
class func preferredCustomFont(forTextStyle textStyle: UIFontTextStyle) -> UIFont {
// we are using the UIFontDescriptor which is less expensive than creating an intermediate UIFont
let systemFontDescriptor = UIFontDescriptor.preferredFontDescriptor(withTextStyle: textStyle)
let customFontDescriptor = UIFontDescriptor.init(fontAttributes: [
UIFontDescriptorFamilyAttribute: CustomFont.fontFamily,
UIFontDescriptorSizeAttribute: systemFontDescriptor.pointSize // use the font size of the default dynamic font
])
// return font of new family with same size as the preferred system font
return UIFont(descriptor: customFontDescriptor, size: 0)
}
}
用法
func userChangedTextSize(notification: NSNotification) {
label.font = UIFont.preferredCustomFont(forTextStyle: .headline)
// or in Bold / Italic:
// label.font = UIFont.preferredCustomFont(forTextStyle: .headline).bolded
// label.font = UIFont.preferredCustomFont(forTextStyle: .headline).italicized
}
关于ios - 在 Swift 3/iOS10 中使用带有自定义字体的动态类型的更好方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41798080/