The above code works perfectly but there is one problem. Overriding the method drawText(in rect: CGRect)
, it loses every benefit of managing of text that is done by UILabel. In fact, the text isn't cut when the text goes out of size of the label.
this is the result of code:


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)
}
*/
}
Utility class with furigana function
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
}
}