利用Swift如何计算文本的size示例详解

前言

对于swift 还处于摸索阶段很多语法还不熟悉,本文主要给大家介绍的是关于利用Swift计算文本size的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。

iOS 11之前限制宽高计算字符串的size用的是UILabel的textRect(forBounds bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect方法,当时也没考虑线程安全问题(low爆了),Xcode也没提示,用了好几个版本,所幸一直都没问题。

贴下方法(当时为什么选这个方法就不解释了):

func textSize(font: UIFont, constrainedSize: CGSize, lineSpacing: CGFloat?, lines: Int) -> CGSize {
    if self.isEmpty || lines < 0 {
      return CGSize.zero
    }

    let attributedString = NSMutableAttributedString(string: self)
    let range = NSRange(location: 0, length: attributedString.length)
    attributedString.addAttributes([NSFontAttributeName: font], range: range)
    if lineSpacing != nil {
      let paragraphStyle = NSMutableParagraphStyle()
      paragraphStyle.lineBreakMode = .byTruncatingTail
      paragraphStyle.lineSpacing = lineSpacing!
      attributedString.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: range)
    }

    let calculatedLabel = UILabel()
    calculatedLabel.font = font
    calculatedLabel.attributedText = attributedString
    calculatedLabel.numberOfLines = lines
    let rect = calculatedLabel.textRect(forBounds: CGRect(x: 0, y: 0, width: constrainedSize.width, height: constrainedSize.height), limitedToNumberOfLines: lines)

    return rect.size
  }

最近升级了Xcode 9,运行时警告我let calculatedLabel = UILabel()要在主线程执行,这时才意识到问题的严重性,马上进行了修改:

extension String {

  func boundingRect(with constrainedSize: CGSize, font: UIFont, lineSpacing: CGFloat? = nil) -> CGSize {
    let attritube = NSMutableAttributedString(string: self)
    let range = NSRange(location: 0, length: attritube.length)
    attritube.addAttributes([NSAttributedStringKey.font: font], range: range)
    if lineSpacing != nil {
      let paragraphStyle = NSMutableParagraphStyle()
      paragraphStyle.lineSpacing = lineSpacing!
      attritube.addAttribute(NSAttributedStringKey.paragraphStyle, value: paragraphStyle, range: range)
    }

    let rect = attritube.boundingRect(with: constrainedSize, options: [.usesLineFragmentOrigin, .usesFontLeading], context: nil)
    var size = rect.size

    if let currentLineSpacing = lineSpacing {
      // 文本的高度减去字体高度小于等于行间距,判断为当前只有1行
      let spacing = size.height - font.lineHeight
      if spacing <= currentLineSpacing && spacing > 0 {
        size = CGSize(width: size.width, height: font.lineHeight)
      }
    }

    return size
  }

  func boundingRect(with constrainedSize: CGSize, font: UIFont, lineSpacing: CGFloat? = nil, lines: Int) -> CGSize {
    if lines < 0 {
      return .zero
    }

    let size = boundingRect(with: constrainedSize, font: font, lineSpacing: lineSpacing)
    if lines == 0 {
      return size
    }

    let currentLineSpacing = (lineSpacing == nil) ? (font.lineHeight - font.pointSize) : lineSpacing!
    let maximumHeight = font.lineHeight*CGFloat(lines) + currentLineSpacing*CGFloat(lines - 1)
    if size.height >= maximumHeight {
      return CGSize(width: size.width, height: maximumHeight)
    }

    return size
  }
}

参数解释

  • constrainedSize:限制的size
  • font:字号
  • lineSpacing:默认为nil,使用系统默认的行间距
  • lines:限制的行数

注:代码版本为Swift 4.0

上面的两个方法分别取代名:方法1和方法2。

方法1:限制宽高,可设置行间距,计算准确

方法2:比方法1多了限制行数功能。

配合使用UILabel的扩展方法:

extension UILabel {

  // 设置`numberOfLines = 0`的原因:
  // 配合方法`func boundingRect(with constrainedSize: CGSize, font: UIFont, lineSpacing: CGFloat? = nil, lines: Int) -> CGSize`使用,可以很好的解决不能正常显示限制行数的问题;
  // 如果为label设置了限制行数(大于0的前提),使用上面的计算方法(带行间距),同时字符串的实际行数大于限制行数,这时候的高度会使label不能正常显示。
  func setText(with normalString: String, lineSpacing: CGFloat?, frame: CGRect) {
    self.frame = frame
    self.numberOfLines = 0

    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.lineBreakMode = .byTruncatingTail
    if lineSpacing != nil {
      if (frame.height - font.lineHeight) <= lineSpacing! {
        paragraphStyle.lineSpacing = 0
      } else {
        paragraphStyle.lineSpacing = lineSpacing!
      }
    }
    let attributedString = NSMutableAttributedString(string: normalString)
    let range = NSRange(location: 0, length: attributedString.length)
    attributedString.addAttributes([NSAttributedStringKey.font: font], range: range)
    attributedString.addAttribute(NSAttributedStringKey.paragraphStyle, value: paragraphStyle, range: range)

    self.attributedText = attributedString
  }
}

在此感谢仓鼠:iOS 行距全攻略https://github.com/zhengwenming/WeChat

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • 利用Swift如何计算文本的size示例详解

    前言 对于swift 还处于摸索阶段很多语法还不熟悉,本文主要给大家介绍的是关于利用Swift计算文本size的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. iOS 11之前限制宽高计算字符串的size用的是UILabel的textRect(forBounds bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect方法,当时也没考虑线程安全问题(low爆了),Xcode也没提示,用了好

  • java 与testng利用XML做数据源的数据驱动示例详解

    java 与testng利用XML做数据源的数据驱动示例详解 testng的功能很强大,利用@DataProvider可以做数据驱动,数据源文件可以是EXCEL,XML,YAML,甚至可以是TXT文本.在这以XML为例: 备注:@DataProvider的返回值类型只能是Object[][]与Iterator<Object>[] TestData.xml: <?xml version="1.0" encoding="UTF-8"?> <

  • Swift进阶教程Mirror反射示例详解

    目录 元类型与.self AnyObject AnyClass Any type(Of:) self self在方法里面的作用 Self Swift Runtime Mirror Mirror的基本用法 Mirror的简单应用-JSON解析 Mirror源码解析 Enum Metadata探索 还原TargetEnumMetadata 还原TargetEnumDescriptor 相对偏移指针 打印枚举中的属性 Struct Metadata探索 获取结构体的属性 swift_getTypeBy

  • 利用Python自动生成PPT的示例详解

    在日常工作中,PPT制作是常见的工作,如果制作创意类PPT,则无法通过自动化的形式生成,因为创意本身具有随机性,而自动化解决的是重复性工作,两者有所冲突. python-pptx是python处理PPT的一个库,注重的是读和写,无法导出,没有渲染功能. 废话不多说,第一步,安装python-pptx库: pip3 install -i https://pypi.doubanio.com/simple/ python-pptx ppt里面处理的主要对象一般为文本框,表格,图片. 每一页的ppt为一

  • Swift 中的 JSON 反序列化示例详解

    目录 业界常用的几种方案 手动解码方案,如 Unbox(DEPRECATED) 阿里开源的 HandyJSON 基于 Sourcery 的元编程方案 Swift build-in API Codable 属性装饰器,如 BetterCodable 各个方案优缺点对比 Codable 介绍 原理浅析 Decoder.Container 协议 自研方案 功能设计 Decoder.Container 具体实现 再议 PropertyWrapper 应用场景示例 单元测试 性能对比 业界常用的几种方案

  • Qt利用QJson实现解析数组的示例详解

    目录 前言 第一步:进行数据转换 第二步:将字符串转成QJsonDocument格式 第三步:解析json数据 前言 现在有这样一个json结构,需要使用QJson来解析,结构如下: "code": "0001", "descrip": "文本描述1详细描述", "id": "1", "title": "文本1标题", "type&quo

  • 利用Pygame制作简单动画的示例详解

    目录 前言 计时器 绘制精灵 加载精灵 完整代码 前言 实现一个帧动画,使用的一个图,根据不同的时间显示不同的图. 使用的就是如下所示的一张图,宽度780 * 300 ,使用加载图片 260 * 150来实现. pygame.init() screen = pygame.display.set_mode((400, 300), 0, 32) pygame.display.set_caption("动画") while True: for event in pygame.event.ge

  • 利用Python创建位置生成器的示例详解

    目录 介绍 开始 步骤 创建训练数据集 创建测试数据集 将合成图像转换回坐标 放在一起 结论 介绍 在这篇文章中,我们将探索如何在美国各地城市的地图数据和公共电动自行车订阅源上训练一个快速生成的对抗网络(GAN)模型. 然后,我们可以通过为包括东京在内的世界各地城市创建合成数据集来测试该模型的学习和概括能力. git clone https://github.com/gretelai/GAN-location-generator.git 在之前的一篇博客中,我们根据电子自行车订阅源中的精确位置数

  • 利用IntersectionObserver实现动态渲染的示例详解

    目录 前言 实现 懒加载组件 长列表组件示意 测试 前言 开发表格时,希望支持可视后的动态加载.在查找资料做了一些尝试后,最终使用IntersectionObserver,相对方便地实现了该功能 IntersectionObserver诞生已经有几年了,所以它的兼容性目前已经达到可以使用的程度了.具体兼容程度以及详细API可参考CDN 实现 懒加载组件 核心就是利用了IntersectionObserver的能力,封装了LazyContainer组件,该组件的children,只有在视口中可见时

  • 利用Python实现智能合约的示例详解

    目录 智能合约 1. 是什么 2. 使用场景 用Python如何实现 1. 设计智能合约 2. 编写智能合约源代码 3. 编译智能合约 4. 部署智能合约 5. 调用智能合约方法 6. 监控智能合约事件 7. 升级智能合约 智能合约 1. 是什么 智能合约是一种由计算机程序编写的自动化合约,它可以在没有第三方干预的情况下执行交易和契约条款.智能合约使用区块链技术实现,可以实现不同的功能,例如交易.投票.代币发放和数据存储等.智能合约的执行是基于其代码的逻辑,并且在既定条件满足时自动执行.智能合约

随机推荐