JKSwiftExtension,测试用例在 JKContentSizeViewController.swift 里面
需求:单行文字可缩放到一定比例,按照Char截取,超出截掉,不允许出现Char被截取一半的情况
一、常规的剪切方式 (lineBreakMode
设置文字过长时的显示格式)
- 1.1、NSLineBreakMode枚举如下
public enum NSLineBreakMode : Int { // 以单词为显示单位显=示,后面部分省略不显示 case byWordWrapping = 0 // 以字符为显示单位显示,后面部分省略不显示。 case byCharWrapping = 1 // 剪切与文本宽度相同的内容长度,后半部分被删除。 case byClipping = 2 // 前面部分文字以……方式省略,显示尾部文字内容 case byTruncatingHead = 3 // 结尾部分的内容以……方式省略,显示头的文字内容 case byTruncatingTail = 4 // 中间的内容以……方式省略,显示头尾的文字内容 case byTruncatingMiddle = 5 }
- 使用如下:以
byWordWrapping
的形式剪切
let label = UILabel(frame: CGRect(x: 20, y: 20, width: 100, height: 19)) label.backgroundColor = .yellow label.font = UIFont.systemFont(ofSize: 10) label.textAlignment = .left label.textColor = UIColor.brown label.lineBreakMode = .byWordWrapping return label
二、本次的需求实现
- 2.1、需求:单行文字可缩放到一定比例,按照Char截取,超出截掉,不允许出现Char被截取一半的情况
- 需求分析:
可缩放一定比例
、按照Char截取
、不允许出现Char被截取一半的情况
- 实现方式:先获取缩放后的字体大小,后获取指定宽度的第一行文字的内容
- 2.2、具体的核心代码如下
public struct JKContentSize {} public extension JKContentSize { // MARK: 2.1、行数和每行的内容 /// 获取已知 width 的 label 的文本行数 & 每一行内容 /// - Parameters: /// - content: 文本的内容 /// - font: 字体 /// - width: 宽度 /// - height: 高度 /// - minimumScaleFactor: 缩放率 /// - Returns: 文本行数 & 每一行内容 static func linesCountAndLinesContent(content: String, font: UIFont, width: CGFloat, height: CGFloat, minimumScaleFactor: CGFloat = 1.0) -> (Int?, [String]?) { let lodFontName = font.fontName let fontSize = getFontSizeForLabel(content: content, minimumScaleFactor: minimumScaleFactor, font: font, width: width, height: height) let newFont = UIFont(name: lodFontName, size: fontSize) ?? UIFont.systemFont(ofSize: fontSize) let c_fn = newFont.fontName as CFString let fp = newFont.pointSize let c_f = CTFontCreateWithName(c_fn, fp, nil) let style = NSMutableParagraphStyle() style.lineBreakMode = .byCharWrapping let contentDict = [NSAttributedString.Key.paragraphStyle : style] as [NSAttributedString.Key : Any] let attr = NSMutableAttributedString(string: content) let range = NSRange(location: 0, length: attr.length) attr.addAttributes(contentDict, range: range) attr.addAttribute(NSAttributedString.Key.font, value: c_f, range: range) let frameSetter = CTFramesetterCreateWithAttributedString(attr as CFAttributedString) let path = CGMutablePath() /// 2.5 是经验误差值 path.addRect(CGRect(x: 0, y: 0, width: width, height: height > (fp * 1.5) ? height : fp * 1.5)) let framef = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, nil) let lines = CTFrameGetLines(framef) as NSArray var lineArr = [String]() for line in lines { let lineRange = CTLineGetStringRange(line as! CTLine) let lineString = content.jk.sub(start: lineRange.location, length: lineRange.length) lineArr.append(lineString as String) } return (lineArr.count, lineArr) } // MARK: 获取字体的大小 /// 获取字体的大小 /// - Returns: 字体的大小 private static func getFontSizeForLabel(content: String, minimumScaleFactor: CGFloat, font: UIFont, width: CGFloat, height: CGFloat) -> CGFloat { let text: NSMutableAttributedString = NSMutableAttributedString(attributedString: NSAttributedString(string: content)) text.setAttributes([NSAttributedString.Key.font: font as Any], range: NSMakeRange(0, text.length)) let context: NSStringDrawingContext = NSStringDrawingContext() context.minimumScaleFactor = minimumScaleFactor text.boundingRect(with: CGSize(width: width, height: height), options: NSStringDrawingOptions.usesLineFragmentOrigin, context: context) let adjustedFontSize: CGFloat = font.pointSize * context.actualScaleFactor return adjustedFontSize } }