Make attributed titles work on iOS
This commit is contained in:
parent
dc787620c5
commit
6aff83481f
|
@ -6,11 +6,29 @@
|
|||
// Copyright © 2020 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
#if canImport(AppKit)
|
||||
import AppKit
|
||||
typealias Font = NSFont
|
||||
typealias FontDescriptor = NSFontDescriptor
|
||||
typealias Color = NSColor
|
||||
|
||||
private let boldTrait = NSFontDescriptor.SymbolicTraits.bold
|
||||
private let italicTrait = NSFontDescriptor.SymbolicTraits.italic
|
||||
private let monoSpaceTrait = NSFontDescriptor.SymbolicTraits.monoSpace
|
||||
#else
|
||||
import UIKit
|
||||
typealias Font = UIFont
|
||||
typealias FontDescriptor = UIFontDescriptor
|
||||
typealias Color = UIColor
|
||||
|
||||
private let boldTrait = UIFontDescriptor.SymbolicTraits.traitBold
|
||||
private let italicTrait = UIFontDescriptor.SymbolicTraits.traitItalic
|
||||
private let monoSpaceTrait = UIFontDescriptor.SymbolicTraits.traitMonoSpace
|
||||
#endif
|
||||
|
||||
extension NSAttributedString {
|
||||
|
||||
func adding(font baseFont: NSFont, color: NSColor? = nil) -> NSAttributedString {
|
||||
func adding(font baseFont: Font, color: Color? = nil) -> NSAttributedString {
|
||||
let mutable = self.mutableCopy() as! NSMutableAttributedString
|
||||
let fullRange = NSRange(location: 0, length: mutable.length)
|
||||
|
||||
|
@ -22,60 +40,68 @@ extension NSAttributedString {
|
|||
let baseDescriptor = baseFont.fontDescriptor
|
||||
let baseSymbolicTraits = baseDescriptor.symbolicTraits
|
||||
|
||||
let baseTraits = baseDescriptor.object(forKey: .traits) as! [NSFontDescriptor.TraitKey: Any]
|
||||
let baseWeight = baseTraits[.weight] as! NSFont.Weight
|
||||
let baseTraits = baseDescriptor.object(forKey: .traits) as! [FontDescriptor.TraitKey: Any]
|
||||
let baseWeight = baseTraits[.weight] as! Font.Weight
|
||||
|
||||
mutable.enumerateAttribute(.font, in: fullRange, options: []) { (font: Any?, range: NSRange, stop: UnsafeMutablePointer<ObjCBool>) in
|
||||
guard let font = font as? NSFont else { return }
|
||||
guard let font = font as? Font else { return }
|
||||
|
||||
var newSymbolicTraits = baseSymbolicTraits
|
||||
|
||||
let symbolicTraits = font.fontDescriptor.symbolicTraits
|
||||
|
||||
if symbolicTraits.contains(.italic) {
|
||||
newSymbolicTraits.insert(.italic)
|
||||
if symbolicTraits.contains(italicTrait) {
|
||||
newSymbolicTraits.insert(italicTrait)
|
||||
}
|
||||
|
||||
if symbolicTraits.contains(.monoSpace) {
|
||||
newSymbolicTraits.insert(.monoSpace)
|
||||
if symbolicTraits.contains(monoSpaceTrait) {
|
||||
newSymbolicTraits.insert(monoSpaceTrait)
|
||||
}
|
||||
|
||||
#if canImport(AppKit)
|
||||
var descriptor = baseDescriptor.withSymbolicTraits(newSymbolicTraits)
|
||||
#else
|
||||
var descriptor = baseDescriptor.withSymbolicTraits(newSymbolicTraits)!
|
||||
#endif
|
||||
|
||||
if symbolicTraits.contains(.bold) {
|
||||
if symbolicTraits.contains(boldTrait) {
|
||||
// If the base font is semibold (as timeline titles are), make the "bold"
|
||||
// text heavy for better contrast.
|
||||
|
||||
if baseWeight == .semibold {
|
||||
let traits: [NSFontDescriptor.TraitKey: Any] = [.weight: NSFont.Weight.heavy]
|
||||
let attributes: [NSFontDescriptor.AttributeName: Any] = [.traits: traits]
|
||||
let traits: [FontDescriptor.TraitKey: Any] = [.weight: Font.Weight.heavy]
|
||||
let attributes: [FontDescriptor.AttributeName: Any] = [.traits: traits]
|
||||
descriptor = descriptor.addingAttributes(attributes)
|
||||
}
|
||||
}
|
||||
|
||||
let newFont = NSFont(descriptor: descriptor, size: size)
|
||||
let newFont = Font(descriptor: descriptor, size: size)
|
||||
|
||||
mutable.addAttribute(.font, value: newFont as Any, range: range)
|
||||
}
|
||||
|
||||
// make sup/sub smaller
|
||||
// make sup/sub smaller. `Key("NSSupeScript")` is used here because `.superscript`
|
||||
// isn't defined in UIKit, for some reason.
|
||||
mutable.enumerateAttributes(in: fullRange, options: []) { (attributes: [Key : Any], range: NSRange, stop: UnsafeMutablePointer<ObjCBool>) in
|
||||
guard let superscript = attributes[.superscript] as? Int else {
|
||||
guard let superscript = attributes[Key("NSSuperScript")] as? Int else {
|
||||
return
|
||||
}
|
||||
|
||||
if superscript != 0 {
|
||||
let font = mutable.attribute(.font, at: range.location, effectiveRange: nil) as! NSFont
|
||||
let font = mutable.attribute(.font, at: range.location, effectiveRange: nil) as! Font
|
||||
|
||||
let features: [NSFontDescriptor.FeatureKey: Any] = [.typeIdentifier: kVerticalPositionType, .selectorIdentifier: superscript > 0 ? kSuperiorsSelector : kInferiorsSelector]
|
||||
let attributes: [NSFontDescriptor.AttributeName: Any] = [.featureSettings: [features]]
|
||||
#if canImport(AppKit)
|
||||
let features: [FontDescriptor.FeatureKey: Any] = [.typeIdentifier: kVerticalPositionType, .selectorIdentifier: superscript > 0 ? kSuperiorsSelector : kInferiorsSelector]
|
||||
#else
|
||||
let features: [FontDescriptor.FeatureKey: Any] = [.featureIdentifier: kVerticalPositionType, .typeIdentifier: superscript > 0 ? kSuperiorsSelector : kInferiorsSelector]
|
||||
#endif
|
||||
let attributes: [FontDescriptor.AttributeName: Any] = [.featureSettings: [features]]
|
||||
let descriptor = font.fontDescriptor.addingAttributes(attributes)
|
||||
|
||||
let newFont = NSFont(descriptor: descriptor, size: font.pointSize)
|
||||
let newFont = Font(descriptor: descriptor, size: font.pointSize)
|
||||
mutable.addAttribute(.font, value: newFont as Any, range: range)
|
||||
mutable.addAttribute(.superscript, value: 0, range: range)
|
||||
mutable.addAttribute(Key("NSSuperScript"), value: 0, range: range)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return mutable.copy() as! NSAttributedString
|
||||
|
|
|
@ -731,6 +731,7 @@
|
|||
B2B8075E239C49D300F191E0 /* RSImage-AppIcons.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2B8075D239C49D300F191E0 /* RSImage-AppIcons.swift */; };
|
||||
B2B80778239C4C7000F191E0 /* RSImage-AppIcons.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2B8075D239C49D300F191E0 /* RSImage-AppIcons.swift */; };
|
||||
B2B80779239C4C7300F191E0 /* RSImage-AppIcons.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2B8075D239C49D300F191E0 /* RSImage-AppIcons.swift */; };
|
||||
B2C0FDEA2447A69100ADC150 /* NSAttributedString+NetNewsWire.swift in Sources */ = {isa = PBXBuildFile; fileRef = B26B9571243D176B0053EEF5 /* NSAttributedString+NetNewsWire.swift */; };
|
||||
B528F81E23333C7E00E735DD /* page.html in Resources */ = {isa = PBXBuildFile; fileRef = B528F81D23333C7E00E735DD /* page.html */; };
|
||||
BDCB516724282C8A00102A80 /* AccountsNewsBlur.xib in Resources */ = {isa = PBXBuildFile; fileRef = BDCB514D24282C8A00102A80 /* AccountsNewsBlur.xib */; };
|
||||
BDCB516824282C8A00102A80 /* AccountsNewsBlur.xib in Resources */ = {isa = PBXBuildFile; fileRef = BDCB514D24282C8A00102A80 /* AccountsNewsBlur.xib */; };
|
||||
|
@ -4307,6 +4308,7 @@
|
|||
51F9F3F923DFB16300A314FD /* UITableView-Extensions.swift in Sources */,
|
||||
51C452792265091600C03939 /* MasterTimelineTableViewCell.swift in Sources */,
|
||||
51C4526B226508F600C03939 /* MasterFeedViewController.swift in Sources */,
|
||||
B2C0FDEA2447A69100ADC150 /* NSAttributedString+NetNewsWire.swift in Sources */,
|
||||
5126EE97226CB48A00C22AFC /* SceneCoordinator.swift in Sources */,
|
||||
84CAFCB022BC8C35007694F0 /* FetchRequestOperation.swift in Sources */,
|
||||
51EF0F77227716200050506E /* FaviconGenerator.swift in Sources */,
|
||||
|
|
|
@ -12,6 +12,7 @@ import Articles
|
|||
struct MasterTimelineCellData {
|
||||
|
||||
let title: String
|
||||
let attributedTitle: NSAttributedString
|
||||
let summary: String
|
||||
let dateString: String
|
||||
let feedName: String
|
||||
|
@ -28,6 +29,7 @@ struct MasterTimelineCellData {
|
|||
init(article: Article, showFeedName: ShowFeedName, feedName: String?, byline: String?, iconImage: IconImage?, showIcon: Bool, featuredImage: UIImage?, numberOfLines: Int, iconSize: IconSize) {
|
||||
|
||||
self.title = ArticleStringFormatter.truncatedTitle(article)
|
||||
self.attributedTitle = ArticleStringFormatter.attributedTruncatedTitle(article)
|
||||
self.summary = ArticleStringFormatter.truncatedSummary(article)
|
||||
|
||||
self.dateString = ArticleStringFormatter.dateString(article.logicalDatePublished)
|
||||
|
@ -60,6 +62,7 @@ struct MasterTimelineCellData {
|
|||
|
||||
init() { //Empty
|
||||
self.title = ""
|
||||
self.attributedTitle = NSAttributedString()
|
||||
self.summary = ""
|
||||
self.dateString = ""
|
||||
self.feedName = ""
|
||||
|
|
|
@ -148,7 +148,7 @@ private extension MasterTimelineTableViewCell {
|
|||
func updateTitleView() {
|
||||
titleView.font = MasterTimelineDefaultCellLayout.titleFont
|
||||
titleView.textColor = labelColor
|
||||
updateTextFieldText(titleView, cellData?.title)
|
||||
updateTextFieldAttributedText(titleView, cellData?.attributedTitle)
|
||||
}
|
||||
|
||||
func updateSummaryView() {
|
||||
|
@ -170,6 +170,19 @@ private extension MasterTimelineTableViewCell {
|
|||
setNeedsLayout()
|
||||
}
|
||||
}
|
||||
|
||||
func updateTextFieldAttributedText(_ label: UILabel, _ text: NSAttributedString?) {
|
||||
var s = text ?? NSAttributedString(string: "")
|
||||
|
||||
if let fieldFont = label.font, let color = label.textColor {
|
||||
s = s.adding(font: fieldFont, color: color)
|
||||
}
|
||||
|
||||
if label.attributedText != s {
|
||||
label.attributedText = s
|
||||
setNeedsLayout()
|
||||
}
|
||||
}
|
||||
|
||||
func updateFeedNameView() {
|
||||
switch cellData.showFeedName {
|
||||
|
|
Loading…
Reference in New Issue