When migrating from Xcode 12.5 to Xcode 13 we bumped into a problem where the rendering of a composed NSMutableAttributedString
from different NSMutableAttributedString
's was not happening correctly anymore. It looks like there's a mismatch in the range of the strikethroughStyle
attribute. In the comparison below you can see that the decimal strikethrough is now on the currency and the other way around.
We have a formatPrice()
function who will append the price NSMutableAttributedString
with the currency NSMutableAttributedString
.
private func formatPrice() {
guard let style = style else { return }
let splitter = AmountSplitter(locale: Locale(identifier: style.siteId.localeIdentifier))
let digitsText = splitter.getDigitsText(Double(price))
let formattedAmount = AmountFormatter.getFormattedAmount(
digitsText: digitsText,
textColor: style.textColor,
integerFont: style.integerFont,
decimalFont: style.decimalFont,
strikethrough: style.strikethrough
)
let currency = AmountFormatter.getFormattedCurrency(
currency: " \(style.siteId.currencySymbol)",
font: style.integerFont,
color: style.textColor,
strikethrough: style.strikethrough
)
let mutableFormattedAmount = [formattedAmount, currency, makePostfix()]
.compactMap { $0 }
.reduce(into: NSMutableAttributedString()) { result, attributedString in
result.append(attributedString)
}
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = style.alignment
mutableFormattedAmount.addAttribute(
.paragraphStyle,
value: paragraphStyle,
range: NSRange(location: 0, length: formattedAmount.length)
)
attributedText = mutableFormattedAmount
adjustsFontSizeToFitWidth = true
}
And we are having the getFormattedAmount
and getFormattedCurrency
functions on AmountFormatter
that returns the formatted amount and currency based on the given style parameters.
public static func getFormattedAmount(digitsText: DigitsText, textColor: UIColor, integerFont: UIFont, decimalFont: UIFont, strikethrough: Bool = false) -> NSAttributedString {
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineBreakMode = .byCharWrapping
let amountAttributed = NSMutableAttributedString()
let fontOffset = integerFont.capHeight - decimalFont.capHeight
let integerAttributed = NSAttributedString(string: digitsText.integers,
attributes: [.font : integerFont,
.foregroundColor: textColor])
let decimalAttributed = NSAttributedString(string: digitsText.decimals,
attributes: [.font : decimalFont,
.baselineOffset: fontOffset,
.foregroundColor: textColor])
amountAttributed.append(integerAttributed)
amountAttributed.append(decimalAttributed)
amountAttributed.addAttributes([.strikethroughStyle: strikethrough ? 1 : 0, .paragraphStyle: paragraphStyle], range: NSRange(location: 0, length: amountAttributed.length))
return amountAttributed
}
public static func getFormattedCurrency(currency: String,
font: UIFont,
color: UIColor,
strikethrough: Bool) -> NSAttributedString {
return NSAttributedString(string: currency,
attributes: [.font : font,
.foregroundColor: color,
.strikethroughStyle: strikethrough ? 1 : 0])
}
This is a specific case with two NSMutableAttributedString
's with the same font
attributes and another NSMutableAttributedString
with another font
and baselineOffset
attributes in between them composed into one NSMutableAttributedString
.
When I change the strikethroughColor
of the currency
to UIColor.red
, the strikethroughStyle
attribute gets rendered correctly.
Anyone experienced the same already?