iOS 10.3: NSStrikethroughStyleAttributeName is not rendered if applied to a sub range of NSMutableAttributedString
A strikethrough (single, double, ...) added as attribute to an instance of NSMutableAttributedString
is not rendered if the apply range is not the whole string range.
This happens using addAttribute(_ name: String, value: Any, range: NSRange)
, insert(_ attrString: NSAttributedString, at loc: Int)
, append(_ attrString: NSAttributedString)
, ...
Broken by Apple in early iOS 10.3 betas, and not fixed in 10.3 final.
Credit: https://openradar.appspot.com/31034683
Setting the baseline offset seems to fix it:
[attributedStr addAttribute:NSBaselineOffsetAttributeName value:@0 range:NSMakeRange(0, 10)];
[attributedStr addAttribute:NSStrikethroughStyleAttributeName value:@2 range:NSMakeRange(0, 10)];
This is a known bug in iOS 10.3
Adding a NSBaselineOffsetAttributeName
, as explained here, to the attributed string brings back the strikethrough line. Overriding drawText:in:
can be slow especially on Collection View or Table View Cells.
Found a workaround for our specific scenario (we don't specify any styling with UILabel's properties, but all with NSAttributedString
attributes):
/// This UILabel subclass accomodates conditional fix for NSAttributedString rendering broken by Apple in iOS 10.3
final class PriceLabel: UILabel {
override func drawText(in rect: CGRect) {
guard let attributedText = attributedText else {
super.drawText(in: rect)
return
}
if #available(iOS 10.3, *) {
attributedText.draw(in: rect)
} else {
super.drawText(in: rect)
}
}
}
NOTE: if you mix UILabel's styling properties with NSAttributedString
attributes, you should think of creating a new attributed string before rendering, apply UILabel's styling on it and then re-apply all attributedText
's attributes over it.
swift 3 working code tested with 10.3
let attributeString: NSMutableAttributedString = NSMutableAttributedString(string: "₹3500")
attributeString.addAttribute(NSBaselineOffsetAttributeName, value: 0, range: NSMakeRange(0, attributeString.length))
attributeString.addAttribute(NSStrikethroughStyleAttributeName, value: 1, range: NSMakeRange(0, attributeString.length))
productPriceLabel.attributedText = attributeString
Swift 4
let text = "Hello World"
let textRange = NSMakeRange(0, text.count)
let attributedText = NSMutableAttributedString(string: text)
attributedText.addAttribute(NSAttributedStringKey.strikethroughStyle,
value: NSUnderlineStyle.styleSingle.rawValue,
range: textRange)
myLabel.attributedText = attributedText