Closed sstadelman closed 6 years ago
Partial answer: supplyDefaults(for attributes: StyleAttributes?) -> StyleAttributes
accomplishes the merging solution, which is very nice.
If anyone else is interested, I did a partial (untested) implementation, that accounts for most of the out-of-box NSAttributedStringKey
's.
init(attributes: [NSAttributedStringKey: Any?]) {
self.init()
var paragraphStyle: NSParagraphStyle? = nil
for pair in attributes {
let key = pair.key, value = pair.value
switch key {
case .paragraphStyle:
paragraphStyle = value as? NSParagraphStyle
case .font:
self.font = value as? BONFont
case .link:
self.link = value as? URL
case .backgroundColor:
self.backgroundColor = value as? BONColor
case .foregroundColor:
self.color = value as? BONColor
case .underlineStyle:
guard let underlineStyle = value as? NSUnderlineStyle else {
self.underline?.0 = .styleNone
break
}
if self.underline == nil {
self.underline = (.styleNone, nil)
}
self.underline?.0 = underlineStyle
case .underlineColor:
if self.underline == nil {
self.underline = (.styleNone, nil)
}
self.underline?.1 = value as? BONColor
case .strikethroughStyle:
guard let strikethroughStyle = value as? NSUnderlineStyle else {
self.strikethrough?.0 = .styleNone
break
}
if self.strikethrough == nil {
self.strikethrough = (.styleNone, nil)
}
self.strikethrough?.0 = strikethroughStyle
case .strikethroughColor:
if self.strikethrough == nil {
self.strikethrough = (.styleNone, nil)
}
self.strikethrough?.1 = value as? BONColor
case .baselineOffset:
self.baselineOffset = value as? CGFloat
case .ligature:
guard let ligature = value as? NSNumber else {
self.ligatures = nil
break
}
self.ligatures = Ligatures(rawValue: ligature.intValue)
case NSAttributedStringKey(UIAccessibilitySpeechAttributePunctuation):
self.speaksPunctuation = value as? Bool
case NSAttributedStringKey(UIAccessibilitySpeechAttributeLanguage):
self.speakingLanguage = value as? String
case NSAttributedStringKey(UIAccessibilitySpeechAttributePitch):
self.speakingPitch = value as? Double
default:
self.extraAttributes.update(possibleValue: value, forKey: key)
}
if #available(iOS 11.0, *) {
switch key {
case NSAttributedStringKey(UIAccessibilitySpeechAttributeIPANotation):
self.speakingPronunciation = value as? String
case NSAttributedStringKey(UIAccessibilitySpeechAttributeQueueAnnouncement):
self.shouldQueueSpeechAnnouncement = value as? Bool
case NSAttributedStringKey(UIAccessibilityTextAttributeHeadingLevel):
guard let level = value as? NSNumber else {
self.headingLevel = nil
break
}
self.headingLevel = HeadingLevel(rawValue: level.intValue)
default:
// Ignore, as these attributes were handled in the unspecialized switch
break
}
} else {
// Ignore, as these attributes are unsupported
}
}
self.lineSpacing = paragraphStyle?.lineSpacing// : CGFloat?
self.paragraphSpacingAfter = paragraphStyle?.paragraphSpacing//: CGFloat?
self.alignment = paragraphStyle?.alignment// : NSTextAlignment?
self.firstLineHeadIndent = paragraphStyle?.firstLineHeadIndent// : CGFloat?
self.headIndent = paragraphStyle?.headIndent
self.tailIndent = paragraphStyle?.tailIndent
self.lineBreakMode = paragraphStyle?.lineBreakMode
self.minimumLineHeight = paragraphStyle?.minimumLineHeight
self.maximumLineHeight = paragraphStyle?.maximumLineHeight
self.baseWritingDirection = paragraphStyle?.baseWritingDirection
self.lineHeightMultiple = paragraphStyle?.lineHeightMultiple
self.paragraphSpacingBefore = paragraphStyle?.paragraphSpacingBefore
self.hyphenationFactor = paragraphStyle?.hyphenationFactor
}
@sstadelman thanks for sharing your implementation! I could definitely see it being useful to initialize a StringStyle
from a dictionary of attributed string attributes. I would consider merging a pull request if you wanted to file one. It should be pretty easy to write some unit tests for it, too.
Question:
Should it be feasible to
init
aStringStyle
from[NSAttributedStringKey: Any?]
? It seems like it would be common-enough scenario, that I wanted to check to see if a) it's already implemented somewhere I'm missing, and b) if not, if there's a good reason why not?Background:
I've been working with
StringStyle
in a UI-controls SDK framework for several month now, and it's really great for maintaining the component styles we get from the Design team in one location in the component (rather than scattered ininit()
andsetup()
and thexib
etc.). We end up with really great abstraction that makes it easy to aggregate various style definitions from the component, and then stylesheets, with implementations like this:The trick though, is that to interact with the non-
StringStyle
providers, I've had to standardize on[NSAttributedStringKey: Any]
, so I'm getting only the most superficial benefit of theStringStyle
. Where I'd really like to get to, is to standardize in the internals onStringStyle
, so that I get the benefits of the composition, especially wrt theNSParagraphStyle
properties.To do that, I think I need to implement something like
StringStyle(attributes: [NSAttributedStringKey: Any?])
. Any concerns?