为 Swift 中的 iOS 字体描述符添加自定义粗细
Add custom weight to iOS Font descriptor in Swift
这看起来应该很简单,但无论出于何种原因,它都不起作用。我在 SO 上读过类似的帖子,看起来 Font Traits 字典可能有问题?这是一个问题还是我完全错过了什么?这是我第一次弄乱这样的字体,所以我认为它可能是后者。
我不想使用常量或提供带有“-bold”变体的字体。我想对字体粗细进行精细控制。
let traits = [UIFontWeightTrait : 1.0]
imgFontDescriptor = UIFontDescriptor(fontAttributes: [UIFontDescriptorNameAttribute: "Helvetica"])
imgFontDescriptor = imgFontDescriptor.fontDescriptorByAddingAttributes([UIFontDescriptorTraitsAttribute:traits])
imgTextFont = UIFont(descriptor: imgFontDescriptor!, size: 24.0)
研究:
- Font Descriptor returns nil in iOS 8
- https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIFontDescriptor_Class/#//apple_ref/doc/constant_group/Font_Traits_Dictionary_Keys
根据 iOS 文档,使用数值应该可行(我是 运行 iOS 9.2):
UIFontWeightTrait
The normalized weight value as an NSNumber object. The valid value range is from -1.0 to 1.0. The value of 0.0 corresponds to the regular or medium font weight. You can also use a font weight constant to specify a particular weight; for a list of constants you can use, see Font Weights. Available in iOS 7.0 and later.
UIFont(descriptor: imgFontDescriptor!, size: 24.0)
是 returning 一个与描述符匹配的字体。如果它找不到与您的描述相匹配的字体,它将 return 设为默认字体。因此,您无法手动控制体重。这取决于您使用的字体。如果字体支持该重量,它将 return 那个。
还有一件事,你应该使用[UIFontDescriptorFamilyAttribute: "Helvetica"]
。因此它将根据 FamilyName 和您的 FontWeight 确定 FontName。
正确的方法是使用 Apple 库中的常量:
public let UIFontWeightUltraLight: CGFloat
@available(iOS 8.2, *)
public let UIFontWeightThin: CGFloat
@available(iOS 8.2, *)
public let UIFontWeightLight: CGFloat
@available(iOS 8.2, *)
public let UIFontWeightRegular: CGFloat
@available(iOS 8.2, *)
public let UIFontWeightMedium: CGFloat
@available(iOS 8.2, *)
public let UIFontWeightSemibold: CGFloat
@available(iOS 8.2, *)
public let UIFontWeightBold: CGFloat
@available(iOS 8.2, *)
public let UIFontWeightHeavy: CGFloat
@available(iOS 8.2, *)
public let UIFontWeightBlack: CGFloat*/
您应该使用 http://iosfonts.com/ 来确定该姓氏支持的字体粗细。
如果是 Helvetica:
let traits = [UIFontWeightTrait: UIFontWeightLight] // UIFontWeightBold / UIFontWeightRegular
let imgFontDescriptor = UIFontDescriptor(fontAttributes: [UIFontDescriptorFamilyAttribute: "Helvetica"])
imgFontDescriptor = imgFontDescriptor.fontDescriptorByAddingAttributes([UIFontDescriptorTraitsAttribute: traits])
如果您使用现有的 fontDescriptor(例如来自现有的字体),它可能无法工作,因为 fontDescriptor.fontAttributes.
中显式的“.name”属性
解决方案,对我有用 (Swift 4):
extension UIFont {
var bold: UIFont { return withWeight(.bold) }
var semibold: UIFont { return withWeight(.semibold) }
private func withWeight(_ weight: UIFont.Weight) -> UIFont {
var attributes = fontDescriptor.fontAttributes
var traits = (attributes[.traits] as? [UIFontDescriptor.TraitKey: Any]) ?? [:]
traits[.weight] = weight
attributes[.name] = nil
attributes[.traits] = traits
attributes[.family] = familyName
let descriptor = UIFontDescriptor(fontAttributes: attributes)
return UIFont(descriptor: descriptor, size: pointSize)
}
}
用法:
let baseFont = UIFont(name: "American Typewriter", size: 20)!
let boldFont = baseFont.bold
let semibold = baseFont.semibold
使用 Swift 4.1,只需执行如下操作:
var descriptor = UIFontDescriptor(name: "Helvetica Neue", size: 24.0)
descriptor = descriptor.addingAttributes([UIFontDescriptor.AttributeName.traits : [UIFontDescriptor.TraitKey.weight : UIFont.Weight.light]])
let font = UIFont(descriptor: descriptor, size: 24.0)
一个简洁的扩展:
extension UIFont {
/// Returns a new font with the weight specified
/// - Parameter weight: The new font weight
func withWeight(_ weight: UIFont.Weight) -> UIFont {
let newDescriptor = fontDescriptor.addingAttributes([.traits: [
UIFontDescriptor.TraitKey.weight: weight]
])
return UIFont(descriptor: newDescriptor, size: pointSize)
}
}
这是 Apple 在他们的 CareKit 框架中 UIFont+Extensions.swift
的扩展:
https://github.com/carekit-apple/CareKit/
extension UIFont {
static func preferredCustomFont(forTextStyle textStyle: TextStyle, weight: Weight) -> UIFont {
let defaultDescriptor = UIFontDescriptor.preferredFontDescriptor(withTextStyle: textStyle)
let size = defaultDescriptor.pointSize
let fontDescriptor = UIFontDescriptor(fontAttributes: [
UIFontDescriptor.AttributeName.size: size,
UIFontDescriptor.AttributeName.family: UIFont.systemFont(ofSize: size).familyName
])
// Add the font weight to the descriptor
let weightedFontDescriptor = fontDescriptor.addingAttributes([
UIFontDescriptor.AttributeName.traits: [
UIFontDescriptor.TraitKey.weight: weight
]
])
return UIFont(descriptor: weightedFontDescriptor, size: 0)
}
}
这看起来应该很简单,但无论出于何种原因,它都不起作用。我在 SO 上读过类似的帖子,看起来 Font Traits 字典可能有问题?这是一个问题还是我完全错过了什么?这是我第一次弄乱这样的字体,所以我认为它可能是后者。
我不想使用常量或提供带有“-bold”变体的字体。我想对字体粗细进行精细控制。
let traits = [UIFontWeightTrait : 1.0]
imgFontDescriptor = UIFontDescriptor(fontAttributes: [UIFontDescriptorNameAttribute: "Helvetica"])
imgFontDescriptor = imgFontDescriptor.fontDescriptorByAddingAttributes([UIFontDescriptorTraitsAttribute:traits])
imgTextFont = UIFont(descriptor: imgFontDescriptor!, size: 24.0)
研究:
- Font Descriptor returns nil in iOS 8
- https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIFontDescriptor_Class/#//apple_ref/doc/constant_group/Font_Traits_Dictionary_Keys
根据 iOS 文档,使用数值应该可行(我是 运行 iOS 9.2):
UIFontWeightTrait
The normalized weight value as an NSNumber object. The valid value range is from -1.0 to 1.0. The value of 0.0 corresponds to the regular or medium font weight. You can also use a font weight constant to specify a particular weight; for a list of constants you can use, see Font Weights. Available in iOS 7.0 and later.
UIFont(descriptor: imgFontDescriptor!, size: 24.0)
是 returning 一个与描述符匹配的字体。如果它找不到与您的描述相匹配的字体,它将 return 设为默认字体。因此,您无法手动控制体重。这取决于您使用的字体。如果字体支持该重量,它将 return 那个。
还有一件事,你应该使用[UIFontDescriptorFamilyAttribute: "Helvetica"]
。因此它将根据 FamilyName 和您的 FontWeight 确定 FontName。
正确的方法是使用 Apple 库中的常量:
public let UIFontWeightUltraLight: CGFloat
@available(iOS 8.2, *)
public let UIFontWeightThin: CGFloat
@available(iOS 8.2, *)
public let UIFontWeightLight: CGFloat
@available(iOS 8.2, *)
public let UIFontWeightRegular: CGFloat
@available(iOS 8.2, *)
public let UIFontWeightMedium: CGFloat
@available(iOS 8.2, *)
public let UIFontWeightSemibold: CGFloat
@available(iOS 8.2, *)
public let UIFontWeightBold: CGFloat
@available(iOS 8.2, *)
public let UIFontWeightHeavy: CGFloat
@available(iOS 8.2, *)
public let UIFontWeightBlack: CGFloat*/
您应该使用 http://iosfonts.com/ 来确定该姓氏支持的字体粗细。
如果是 Helvetica:
let traits = [UIFontWeightTrait: UIFontWeightLight] // UIFontWeightBold / UIFontWeightRegular
let imgFontDescriptor = UIFontDescriptor(fontAttributes: [UIFontDescriptorFamilyAttribute: "Helvetica"])
imgFontDescriptor = imgFontDescriptor.fontDescriptorByAddingAttributes([UIFontDescriptorTraitsAttribute: traits])
如果您使用现有的 fontDescriptor(例如来自现有的字体),它可能无法工作,因为 fontDescriptor.fontAttributes.
中显式的“.name”属性解决方案,对我有用 (Swift 4):
extension UIFont {
var bold: UIFont { return withWeight(.bold) }
var semibold: UIFont { return withWeight(.semibold) }
private func withWeight(_ weight: UIFont.Weight) -> UIFont {
var attributes = fontDescriptor.fontAttributes
var traits = (attributes[.traits] as? [UIFontDescriptor.TraitKey: Any]) ?? [:]
traits[.weight] = weight
attributes[.name] = nil
attributes[.traits] = traits
attributes[.family] = familyName
let descriptor = UIFontDescriptor(fontAttributes: attributes)
return UIFont(descriptor: descriptor, size: pointSize)
}
}
用法:
let baseFont = UIFont(name: "American Typewriter", size: 20)!
let boldFont = baseFont.bold
let semibold = baseFont.semibold
使用 Swift 4.1,只需执行如下操作:
var descriptor = UIFontDescriptor(name: "Helvetica Neue", size: 24.0)
descriptor = descriptor.addingAttributes([UIFontDescriptor.AttributeName.traits : [UIFontDescriptor.TraitKey.weight : UIFont.Weight.light]])
let font = UIFont(descriptor: descriptor, size: 24.0)
一个简洁的扩展:
extension UIFont {
/// Returns a new font with the weight specified
/// - Parameter weight: The new font weight
func withWeight(_ weight: UIFont.Weight) -> UIFont {
let newDescriptor = fontDescriptor.addingAttributes([.traits: [
UIFontDescriptor.TraitKey.weight: weight]
])
return UIFont(descriptor: newDescriptor, size: pointSize)
}
}
这是 Apple 在他们的 CareKit 框架中 UIFont+Extensions.swift
的扩展:
https://github.com/carekit-apple/CareKit/
extension UIFont {
static func preferredCustomFont(forTextStyle textStyle: TextStyle, weight: Weight) -> UIFont {
let defaultDescriptor = UIFontDescriptor.preferredFontDescriptor(withTextStyle: textStyle)
let size = defaultDescriptor.pointSize
let fontDescriptor = UIFontDescriptor(fontAttributes: [
UIFontDescriptor.AttributeName.size: size,
UIFontDescriptor.AttributeName.family: UIFont.systemFont(ofSize: size).familyName
])
// Add the font weight to the descriptor
let weightedFontDescriptor = fontDescriptor.addingAttributes([
UIFontDescriptor.AttributeName.traits: [
UIFontDescriptor.TraitKey.weight: weight
]
])
return UIFont(descriptor: weightedFontDescriptor, size: 0)
}
}