Swift:UILabel超出宽度文字的截取

时间:2021-7-21 作者:qvyue

JKSwiftExtension,测试用例在 JKContentSizeViewController.swift 里面
需求:单行文字可缩放到一定比例,按照Char截取,超出截掉,不允许出现Char被截取一半的情况

Swift:UILabel超出宽度文字的截取
效果图

一、常规的剪切方式 (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
        }
    }
声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:qvyue@qq.com 进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。