Swift 4 CTRubyAnnotation不起作用

对于我的应用程序,几个月前,我已经从这个网站的代码使用CTRubyAnnotation。

这个代码,几乎没有变化,使迅速4工作,完美的工作。

从这个工作中,我创build了一个类,在其中我写了一个函数来使用该代码。

这是快速的4级

import UIKit extension String { func find(pattern: String) -> NSTextCheckingResult? { do { let re = try NSRegularExpression(pattern: pattern, options: []) return re.firstMatch( in: self, options: [], range: NSMakeRange(0, self.utf16.count)) } catch { return nil } } func replace(pattern: String, template: String) -> String { do { let re = try NSRegularExpression(pattern: pattern, options: []) return re.stringByReplacingMatches( in: self, options: [], range: NSMakeRange(0, self.utf16.count), withTemplate: template) } catch { return self } } } class Utility: NSObject { class var sharedInstance: Utility { struct Singleton { static let instance = Utility() } return Singleton.instance } func furigana(String:String) -> NSMutableAttributedString { let attributed = String .replace(pattern: "(|.+?《.+?》)", template: ",$1,") .components(separatedBy: ",") .map { x -> NSAttributedString in if let pair = x.find(pattern: "|(.+?)《(.+?)》") { let string = (x as NSString).substring(with: pair.range(at: 1)) let ruby = (x as NSString).substring(with: pair.range(at: 2)) var text: [Unmanaged<CFString>?] = [Unmanaged<CFString>.passRetained(ruby as CFString) as Unmanaged<CFString>, .none, .none, .none] let annotation = CTRubyAnnotationCreate(CTRubyAlignment.auto, CTRubyOverhang.auto, 0.5, &text[0]) return NSAttributedString( string: string, attributes: [kCTRubyAnnotationAttributeName as NSAttributedStringKey: annotation]) } else { return NSAttributedString(string: x, attributes: nil) } } .reduce(NSMutableAttributedString()) { $0.append($1); return $0 } let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineHeightMultiple = 1.5 paragraphStyle.lineSpacing = 12 attributed.addAttribute(NSAttributedStringKey.paragraphStyle, value:paragraphStyle, range:NSMakeRange(0, (attributed.length))) attributed.addAttributes([NSAttributedStringKey.font: UIFont(name: "HiraMinProN-W3", size: 14.0)!, NSAttributedStringKey.verticalGlyphForm: false,],range: NSMakeRange(0, (attributed.length))) return attributed } } 

我不知道为什么,但这个代码不起作用。

这是使用这个函数的类:

 class ViewController: UIViewController { @IBOutlet weak var furiganaLabel: UILabel! override func viewDidLoad() { furiganaLabel.attributedText = Utility.sharedInstance.furigana(String: "|優勝《ゆうしょう》の|懸《か》かった|試合《しあい》。") } } 

这是结果: 结果与我的function

但是,与原来的代码完美的工作: 使用原始代码

有人可以帮我解释一下原因吗?

非常感谢你

上面的代码完美的工作,但有一个问题。 重写方法drawText(in rect: CGRect) ,它失去了由UILabel完成的文本pipe理的所有好处。 事实上,当文本超出标签大小时,文本不会被剪切。

这是代码的结果: 垂直结果

景观结果

CustomTableViewCell

  import UIKit class CustomTableViewCell: UITableViewCell { let userDefaults = UserDefaults.standard var japaneseKanji = ""{ didSet{ if japaneseKanji != oldValue { japaneseKanjiLabel.attributedText = Utility.sharedInstance.furigana(String: japaneseKanji) } } } var japaneseRomaji = ""{ didSet{ if japaneseRomaji != oldValue { japaneseRomajiLabel.text = japaneseRomaji } } } var italianText = ""{ didSet{ if italianText != oldValue { italianLabel.text = italianText } } } var englishText = ""{ didSet{ if englishText != oldValue { englishLabel.text = englishText } } } private var japaneseImage = UIImageView() private var romajiImage = UIImageView() private var italianImage = UIImageView() private var englishImage = UIImageView() private var japaneseKanjiLabel = GQAsianLabel() //private var japaneseKanjiLabel = UILabel() private var japaneseRomajiLabel = UILabel() private var italianLabel = UILabel() private var englishLabel = UILabel() override init(style: UITableViewCellStyle, reuseIdentifier: String?){ super.init(style: style, reuseIdentifier: reuseIdentifier) let japaneseImageRect = CGRect(x: 16, y: 14, width: 25, height: 25) japaneseImage = UIImageView(frame: japaneseImageRect) japaneseImage.translatesAutoresizingMaskIntoConstraints = false japaneseImage.image = UIImage(named: "jp") self.contentView.addSubview(japaneseImage) let romajiImageRect = CGRect(x: 16, y: 50, width: 25, height: 25) romajiImage = UIImageView(frame: romajiImageRect) romajiImage.translatesAutoresizingMaskIntoConstraints = false romajiImage.image = UIImage(named: "romaji") self.contentView.addSubview(romajiImage) let italianImageRect = CGRect(x: 16, y: 86, width: 25, height: 25) italianImage = UIImageView(frame: italianImageRect) italianImage.translatesAutoresizingMaskIntoConstraints = false italianImage.image = UIImage(named: "it") self.contentView.addSubview(italianImage) let japaneseKanjiLabelRect = CGRect(x: 62, y: 8, width: 280, height: 46) japaneseKanjiLabel = GQAsianLabel(frame: japaneseKanjiLabelRect) japaneseKanjiLabel.isVertical = false //japaneseKanjiLabel = UILabel(frame: japaneseKanjiLabelRect) japaneseKanjiLabel.numberOfLines = 0 japaneseKanjiLabel.translatesAutoresizingMaskIntoConstraints = false japaneseKanjiLabel.font = UIFont(name: "YuKyo_Yoko-Medium", size: 17) japaneseKanjiLabel.sizeToFit() japaneseKanjiLabel.backgroundColor = UIColor.brown self.contentView.addSubview(japaneseKanjiLabel) let japaneseRomajiLabelRect = CGRect(x: 62, y: 52, width: 280, height: 21) japaneseRomajiLabel = UILabel(frame: japaneseRomajiLabelRect) japaneseRomajiLabel.textAlignment = .left japaneseRomajiLabel.numberOfLines = 0 japaneseRomajiLabel.translatesAutoresizingMaskIntoConstraints = false japaneseRomajiLabel.font = UIFont(name: "HelveticaNeueLTPro-Lt", size: 14) self.contentView.addSubview(japaneseRomajiLabel) let italianLabelRect = CGRect(x: 62, y: 90, width: 280, height: 21) italianLabel = UILabel(frame: italianLabelRect) italianLabel.textAlignment = .left italianLabel.numberOfLines = 0; italianLabel.translatesAutoresizingMaskIntoConstraints = false italianLabel.font = UIFont(name: "HelveticaNeueLTPro-Lt", size: 14) self.contentView.addSubview(italianLabel) let englishImageRect = CGRect(x: 16, y: 122, width: 25, height: 25) englishImage = UIImageView(frame: englishImageRect) englishImage.translatesAutoresizingMaskIntoConstraints = false englishImage.image = UIImage(named: "en") self.contentView.addSubview(englishImage) let englishLabelRect = CGRect(x: 62, y: 138, width: 280, height: 21) englishLabel = UILabel(frame: englishLabelRect) englishLabel.textAlignment = .left englishLabel.numberOfLines = 0 englishLabel.translatesAutoresizingMaskIntoConstraints = false englishLabel.font = UIFont(name: "HelveticaNeueLTPro-Lt", size: 13) self.contentView.addSubview(englishLabel) let englishLanguage = userDefaults.object(forKey: "EnglishLang") as! String let isThereEnglish = userDefaults.object(forKey: "isThereEnglish") as! String let viewDictionary = ["japaneseImage":japaneseImage, "romajiImage":romajiImage, "italianImage":italianImage, "englishImage":englishImage, "kanjiLabel":japaneseKanjiLabel, "romajiLabel":japaneseRomajiLabel, "italianLabel":italianLabel, "englishLabel":englishLabel] as [String : AnyObject] let japaneseImage_H = NSLayoutConstraint.constraints(withVisualFormat: "H:[japaneseImage(25)]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewDictionary) let japaneseImage_V = NSLayoutConstraint.constraints(withVisualFormat: "V:[japaneseImage(25)]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewDictionary) let japaneseImage_POS_H = NSLayoutConstraint.constraints(withVisualFormat: "H:|-16-[japaneseImage]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewDictionary) let japaneseKanji_POS_H = NSLayoutConstraint.constraints(withVisualFormat: "H:[japaneseImage]-21-[kanjiLabel]-8-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewDictionary) let japaneseKanji_POS_V = NSLayoutConstraint.constraints(withVisualFormat: "V:|-10-[kanjiLabel]-20-[romajiLabel]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewDictionary) self.contentView.addConstraint(NSLayoutConstraint.init(item: japaneseImage, attribute: NSLayoutAttribute.centerY, relatedBy: NSLayoutRelation.equal, toItem: japaneseKanjiLabel, attribute: NSLayoutAttribute.centerY, multiplier: 1.0, constant: 0)) let romajiImage_H = NSLayoutConstraint.constraints(withVisualFormat: "H:[romajiImage(25)]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewDictionary) let romajiImage_V = NSLayoutConstraint.constraints(withVisualFormat: "V:[romajiImage(25)]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewDictionary) let romajiImage_POS_H = NSLayoutConstraint.constraints(withVisualFormat: "H:|-16-[romajiImage]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewDictionary) let romajiLabel_POS_H = NSLayoutConstraint.constraints(withVisualFormat: "H:[romajiImage]-21-[romajiLabel]-8-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewDictionary) let romajiLabel_POS_V = NSLayoutConstraint.constraints(withVisualFormat: "V:[romajiLabel]-20-[italianLabel]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewDictionary) self.contentView.addConstraint(NSLayoutConstraint.init(item: romajiImage, attribute: NSLayoutAttribute.centerY, relatedBy: NSLayoutRelation.equal, toItem: japaneseRomajiLabel, attribute: NSLayoutAttribute.centerY, multiplier: 1.0, constant: 0)) let italianImage_H = NSLayoutConstraint.constraints(withVisualFormat: "H:[italianImage(25)]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewDictionary) let italianImage_V = NSLayoutConstraint.constraints(withVisualFormat: "V:[italianImage(25)]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewDictionary) let italianImage_POS_H = NSLayoutConstraint.constraints(withVisualFormat: "H:|-16-[italianImage]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewDictionary) let italianLabel_POS_H = NSLayoutConstraint.constraints(withVisualFormat: "H:[italianImage]-21-[italianLabel]-8-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewDictionary) self.contentView.addConstraint(NSLayoutConstraint.init(item: italianImage, attribute: NSLayoutAttribute.centerY, relatedBy: NSLayoutRelation.equal, toItem: italianLabel, attribute: NSLayoutAttribute.centerY, multiplier: 1.0, constant: 0)) let englishImage_H = NSLayoutConstraint.constraints(withVisualFormat: "H:[englishImage(25)]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewDictionary) let englishImage_V = NSLayoutConstraint.constraints(withVisualFormat: "V:[englishImage(25)]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewDictionary) let englishImage_POS_H = NSLayoutConstraint.constraints(withVisualFormat: "H:|-16-[englishImage]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewDictionary) let englishLabel_POS_H = NSLayoutConstraint.constraints(withVisualFormat: "H:[englishImage]-21-[englishLabel]-8-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewDictionary) self.contentView.addConstraint(NSLayoutConstraint.init(item: englishImage, attribute: NSLayoutAttribute.centerY, relatedBy: NSLayoutRelation.equal, toItem: englishLabel, attribute: NSLayoutAttribute.centerY, multiplier: 1.0, constant: 0)) japaneseImage.addConstraints(japaneseImage_H) japaneseImage.addConstraints(japaneseImage_V) self.contentView.addConstraints(japaneseImage_POS_H) self.contentView.addConstraints(japaneseKanji_POS_H) self.contentView.addConstraints(japaneseKanji_POS_V) romajiImage.addConstraints(romajiImage_H) romajiImage.addConstraints(romajiImage_V) self.contentView.addConstraints(romajiImage_POS_H) self.contentView.addConstraints(romajiLabel_POS_H) self.contentView.addConstraints(romajiLabel_POS_V) italianImage.addConstraints(italianImage_H) italianImage.addConstraints(italianImage_V) self.contentView.addConstraints(italianImage_POS_H) self.contentView.addConstraints(italianLabel_POS_H) englishImage.addConstraints(englishImage_H) englishImage.addConstraints(englishImage_V) self.contentView.addConstraints(englishImage_POS_H) self.contentView.addConstraints(englishLabel_POS_H) if englishLanguage == "ON" && isThereEnglish == "True" { englishImage.alpha = 1.0 englishLabel.alpha = 1.0 let englishLabel_POS_V = NSLayoutConstraint.constraints(withVisualFormat: "V:[italianLabel]-20-[englishLabel]-10-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewDictionary) self.contentView.addConstraints(englishLabel_POS_V) }else{ englishImage.alpha = 0.0 englishLabel.alpha = 0.0 let italianLabel_POS_V = NSLayoutConstraint.constraints(withVisualFormat: "V:[italianLabel]-10-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewDictionary) self.contentView.addConstraints(italianLabel_POS_V) } } required init(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func awakeFromNib() { super.awakeFromNib() // Initialization code } override func setSelected(_ selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) // Configure the view for the selected state } } 

GQAsianLabel

  import UIKit protocol SimpleVerticalGlyphViewProtocol { } extension SimpleVerticalGlyphViewProtocol { func drawContext(_ attributed:NSMutableAttributedString, textDrawRect:CGRect, isVertical:Bool) { guard let context = UIGraphicsGetCurrentContext() else { return } var path:CGPath if isVertical { context.rotate(by: .pi / 2) context.scaleBy(x: 1.0, y: -1.0) path = CGPath(rect: CGRect(x: textDrawRect.origin.y, y: textDrawRect.origin.x, width: textDrawRect.height, height: textDrawRect.width), transform: nil) } else { context.textMatrix = CGAffineTransform.identity context.translateBy(x: 0, y: textDrawRect.height) context.scaleBy(x: 1.0, y: -1.0) path = CGPath(rect: textDrawRect, transform: nil) } let fontRef = UIFont(name: "Hiragino Sans", size: 17) attributed.addAttribute(kCTFontAttributeName as NSAttributedStringKey, value: fontRef!, range:NSMakeRange(0, attributed.length)) let framesetter = CTFramesetterCreateWithAttributedString(attributed) let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, attributed.length), path, nil) CTFrameDraw(frame, context) } } class GQAsianLabel: UILabel, SimpleVerticalGlyphViewProtocol { var isVertical = false // Only override draw() if you perform custom drawing. // An empty implementation adversely affects performance during animation. override func draw(_ rect: CGRect) { // Drawing code let attributed = NSMutableAttributedString(attributedString: self.attributedText!) //let isVertical = false // if Vertical Glyph, true. attributed.addAttributes([NSAttributedStringKey.verticalGlyphForm: isVertical], range: NSMakeRange(0, attributed.length)) drawContext(attributed, textDrawRect: rect, isVertical: isVertical) } /* override func drawText(in rect: CGRect) { let attributed = NSMutableAttributedString(attributedString: self.attributedText!) //let isVertical = false // if Vertical Glyph, true. attributed.addAttributes([NSAttributedStringKey.verticalGlyphForm: isVertical], range: NSMakeRange(0, attributed.length)) drawContext(attributed, textDrawRect: rect, isVertical: isVertical) } */ } 

具有furiganafunction的实用程序类

  import UIKit extension String { func find(pattern: String) -> NSTextCheckingResult? { do { let re = try NSRegularExpression(pattern: pattern, options: []) return re.firstMatch( in: self, options: [], range: NSMakeRange(0, self.utf16.count)) } catch { return nil } } func replace(pattern: String, template: String) -> String { do { let re = try NSRegularExpression(pattern: pattern, options: []) return re.stringByReplacingMatches( in: self, options: [], range: NSMakeRange(0, self.utf16.count), withTemplate: template) } catch { return self } } } class Utility: NSObject { class var sharedInstance: Utility { struct Singleton { static let instance = Utility() } return Singleton.instance } func furigana(String:String) -> NSMutableAttributedString { let attributed = String .replace(pattern: "(|.+?《.+?》)", template: ",$1,") .components(separatedBy: ",") .map { x -> NSAttributedString in if let pair = x.find(pattern: "|(.+?)《(.+?)》") { let string = (x as NSString).substring(with: pair.range(at: 1)) let ruby = (x as NSString).substring(with: pair.range(at: 2)) var text: [Unmanaged<CFString>?] = [Unmanaged<CFString>.passRetained(ruby as CFString) as Unmanaged<CFString>, .none, .none, .none] let annotation = CTRubyAnnotationCreate(CTRubyAlignment.auto, CTRubyOverhang.auto, 0.5, &text[0]) return NSAttributedString( string: string, attributes: [kCTRubyAnnotationAttributeName as NSAttributedStringKey: annotation]) } else { return NSAttributedString(string: x, attributes: nil) } } .reduce(NSMutableAttributedString()) { $0.append($1); return $0 } let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineHeightMultiple = 1 paragraphStyle.lineSpacing = 0 attributed.addAttribute(NSAttributedStringKey.paragraphStyle, value:paragraphStyle, range:NSMakeRange(0, (attributed.length))) return attributed } } 

我有同样的问题。
Swift4的代码在iOS10上正常工作。 它在iOS11上无法正常工作。
在iOS 11上,似乎UILabel的NSAttributedString发生了变化。
我写了一个通用程序在CoreText中绘制垂直书写字符。 在CoreText中,NSAttributedString也可以在iOS11上运行。 虽然这是一个临时的方法,但是你可以通过使用CoreText来避免这个问题。
我写了示例代码。 由于这将字符直接绘制到上下文中,因此不需要使用UILabel,而是使用UILabel的drawText进行绘制。

 import UIKit protocol SimpleVerticalGlyphViewProtocol { } extension SimpleVerticalGlyphViewProtocol { func drawContext(_ attributed:NSMutableAttributedString, textDrawRect:CGRect, isVertical:Bool) { guard let context = UIGraphicsGetCurrentContext() else { return } var path:CGPath if isVertical { context.rotate(by: .pi / 2) context.scaleBy(x: 1.0, y: -1.0) path = CGPath(rect: CGRect(x: textDrawRect.origin.y, y: textDrawRect.origin.x, width: textDrawRect.height, height: textDrawRect.width), transform: nil) } else { context.textMatrix = CGAffineTransform.identity context.translateBy(x: 0, y: textDrawRect.height) context.scaleBy(x: 1.0, y: -1.0) path = CGPath(rect: textDrawRect, transform: nil) } let framesetter = CTFramesetterCreateWithAttributedString(attributed) let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, attributed.length), path, nil) CTFrameDraw(frame, context) } } 

而且,像下面一样使用它。

 import UIKit class ViewController: UIViewController { @IBOutlet weak var furiganaLabel: CustomLabel! override func viewDidLoad() { super.viewDidLoad() furiganaLabel.attributedText = Utility.sharedInstance.furigana(String: "|優勝《ゆうしょう》の|懸《か》かった|試合《しあい》。") } } class CustomLabel: UILabel, SimpleVerticalGlyphViewProtocol { //override func draw(_ rect: CGRect) { // if not has drawText, use draw UIView etc override func drawText(in rect: CGRect) { let attributed = NSMutableAttributedString(attributedString: self.attributedText!) let isVertical = false // if Vertical Glyph, true. attributed.addAttributes([NSAttributedStringKey.verticalGlyphForm: isVertical], range: NSMakeRange(0, attributed.length)) drawContext(attributed, textDrawRect: rect, isVertical: isVertical) } } 

我添加了适应SimpleVerticalGlyphViewProtocol的CustomLabel类。
请将CustomLabel类设置为Storyboard上的UILabel的自定义类。

字体大小自动缩放,并指定行号0

固定字体大小,指定行号4,基线alignCenters和最后一行被截断。

字体大小自动缩放,并用Ruby指定行号0