摘要

拿来即用短时间效率虽然挺高的,但是拿来的东西没有消化一次,就无法得心应手的使用它。

这次的探索思路就是,查询官方文档,设置不同的值测试单个方法中参数的变化,之后测试两个方法的执行顺序,处理的思路,最后思考总结。

在总结方法的处理逻辑时,使用伪代码的方式梳理方法的执行思路。避免解释文本太多,增加理解的成本。

最近在学习小程序开发,接触到 flex 方式布局,很喜欢这种快速和方便的方式。所以当遇到一个页面上居中显示文本的需求的时候,就想直接在 UIlabel 上处理,然后在UIlabel上设置它的内边距(类似 flex 布局)。而不是先放一个 View。然后在这个view 上放置一个 UILabel 控件,通过设置 UILabel 控件距离父 View 的距离实现。

先看代码实现,下面的代码,是搜索之后的解决方式,如果只是拿去使用,直接复制到项目中即可。需要在设置text前设置textInsets

class SHLabel: UILabel {

   var textInsets: UIEdgeInsets = .zero

   override func drawText(in rect: CGRect) {
       super.drawText(in: rect.inset(by: textInsets))
   }
   
   override func textRect(forBounds bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect {
       
       let insets = textInsets
       var rect = super.textRect(forBounds: bounds.inset(by: insets), limitedToNumberOfLines: numberOfLines)
       
       rect.origin.x -= insets.left
       rect.origin.y -= insets.top
       rect.size.width += (insets.left + insets.right)
       rect.size.height += (insets.top + insets.bottom)
       return rect
   }
}

为什么这种方式可以实现内边距?

接下来是梳理一下,为什么这样实现。首先查看开发者文档,看代码块中这两个方法是做什么的

函数 drawText(in rect: CGRect) textRect(forBounds bounds:, limitedToNumberOfLines numberOfLines) -> CGRect
标题 rect的区域中绘制文本或者阴影 返回文本的绘制的 rect 区域
详细 如果需要修改 label 中的绘图行为,需要重写这个方法。这个方法已经配置用于绘图的默认环境和文本颜色,在重写的方法中,可以自定义绘制方法,然后调用super或者自己进行绘图。 在系统执行其他文本计算之前重写这个方法(这个太难理解),如果调用 sizeToFit()sizeThatFits(_:)会触发这个方法
链接 https://developer.apple.com/documentation/uikit/uilabel/1620527-drawtext https://developer.apple.com/documentation/uikit/uilabel/1620545-textrect

之后验证这两个方法的执行顺序,和各自的作用时,发现当 UILabel 的 text 赋值时,会首先调用textRect方法,之后drawText方法被调用。

textRect在当文本rect的实际宽度大于设置UILabel的实际宽度时,会再次被调用,当然drawText也是在textRect两次调用之后被调用。

textRect 的作用

看到这里,似乎可以理解开发者文档中提到的在系统执行其他文本计算之前重写这个方法了。这个方法的作用就是先获取 UILabel 的 bounds 和 text 的行数,通过调用 super 方法计算出 text 的 rect 区域,返回给系统。

经过多次测试验证发现执行逻辑(伪代码):

  // frame 是设置 UIlabel 时的 frame
  if numberOfLines == 1 {
      textRect 被调用
      return retc 的 width = text 的 widht
  } else {
      if text 文本的 width < frame 的 width {
          text Rect 被调用
          return retc 的 width = text 的 widht
      } else {
          text Rect 被调用两次后
   
          以 frame 的 wdith 为限制,计算出 text 的 height
          return rect 的 size = (frame 的 width,text 的 height)
      }
  }

drawText 的作用

drawText中的rect参数,就是textRect方法返回的rect。text文本的实际绘制区域就通过重写drawText方法,并在其中调用它的super方法实现。

经过多次验证,这里的rect并不完全是textRect方法中返回的rect。它们之间的关系是(伪代码):

  // frame 是设置 UILabel 的 frame
  // rect 是 `textRect` 返回的
  dx = frame.x
  dy = frame.y
  if frame.width 确定不变 {
      dwidth = frame.width
  } else {
      dwidth = rect.width
  }
  if frame.height 确定不变 {
      dheight = frame.height
  } else {
      dheight = rect.width
  }
   
  return drawText 中的 rect(dx,dy,dwidth,dheight)

再问:为什么用这种方式实现内边距?

耐心看完这两个方法之后,对题目中的问题,多少有些思路了。那么就理顺一下这个思路。

首先确定一个共识,就是设置UILabel的内边距,是确定UILabel的frame区域里面,调整text的显示区域。有了这个共识,接下来就好办了。

  • 第一步就要用textRect方法获取到text的显示区域,默认text的显示区域和UILabel的bounds区域是一样的

  • 那就需要和咱们自己设置的内边距值计算获取到新的text文本的rect区域。

  • 最后就用drawText方法重新绘制一下text的rect区域显示。

那么为什么要用这种方式实现呢?因为目前只有这两个方法和 text 文本直接有关系。

优化

理论搞了这么多,到了输出一些干货的时候了。

如果,UILabel的frame已经确定了,重要的是width和height确定了。那么textRect方法就可以不用重写。

class SHLabel: UILabel {

   var textInsets: UIEdgeInsets = .zero
   override func drawText(in rect: CGRect) {
       super.drawText(in: rect.inset(by: textInsets))
   }
}

这里就可以看出,当UILabel的height不确定时,重写textRect来帮忙确定UILabel的高度。经过验证下来,这个方法中的 x 和 y 也是不用处理的,什么时候会用到它?我目前还没有遇到。

class SHLabel: UILabel {

   var textInsets: UIEdgeInsets = .zero

   override func drawText(in rect: CGRect) {
       super.drawText(in: rect.inset(by: textInsets))
   }
   
   override func textRect(forBounds bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect {
       let insets = textInsets
       var rect = super.textRect(forBounds: bounds.inset(by: insets), limitedToNumberOfLines: numberOfLines)

//       rect.origin.x -= insets.left
//       rect.origin.y -= insets.top
       rect.size.width += (insets.left + insets.right)
       rect.size.height += (insets.top + insets.bottom)
       return rect
   }
}

扩展

文章到这里,就结束了。如果你是一个细节控,感觉textRect在需要还是不需要的时候都被调用。drawText方法,不管设置还是不设置内边距也总是被调用,会不会影响性能啊?

这里提供两个方法解决:

  1. 可操作性的,就是尽量考虑需求,在不得不用的时候再使用

  2. 心理安慰性质的,那就是放下。细想一下,这两个方法都是重写的方法,重写的本质是什么?那就是不执行自己的方法,执行重写的方法。换句话说,就算系统不走重写的方法,也要走自己的方法。而这些代码对性能的影响,不值一提。

新发现

突然之间,有没有发现,咱们似乎也明白了,为什么UILabel不用固定它的height,它就可以自己确定高度,完全展示 text文本?你想.你细想...

Swift- 设置 UILabel 内边距的更多相关文章

  1. 可以简易设置文字内边距的EdgeInsetsLabel

    可以简易设置文字内边距的EdgeInsetsLabel 最终效果: 源码: EdgeInsetsLabel.h 与 EdgeInsetsLabel.m // // EdgeInsetsLabel.h ...

  2. W3School-CSS 内边距 (padding) 实例

    CSS 内边距 (padding) 实例 CSS 实例 CSS 背景实例 CSS 文本实例 CSS 字体(font)实例 CSS 边框(border)实例 CSS 外边距 (margin) 实例 CS ...

  3. CSS.03 -- 浏览器行高、字体;盒子模型--边框、内边距、外边距

    如果此时你也在自学中,请使用 FireWorks CS6 进行切图测距等,百度一下吧~ Fireworks的基本使用 新建文件   ctrl+n 打开文件  ctrl+o 调出和隐藏标尺 ctrl+r ...

  4. 谈谈tableView的重要属性内边距

    全屏穿透效果需要做到两点 tableView的可视范围占据整个父控件(或者屏幕)--设置contentsize滚动范围. 所有的cell都可以被看到,也就是说tableView中的cell不会被导航栏 ...

  5. CSS 内边距 (padding) 实例

    CSS 内边距 (padding) 实例元素的内边距在边框和内容区之间.控制该区域最简单的属性是 padding 属性. CSS padding 属性定义元素边框与元素内容之间的空白区域.CSS 内边 ...

  6. CSS 内边距 padding 属性

    CSS padding 属性定义元素边框与元素内容之间的空白区域. ㈠padding(填充) ⑴当元素的 padding(填充)内边距被清除时,所释放的区域将会受到元素背景颜色的填充. ⑵单独使用 p ...

  7. 【Swift】UILabel 设置内边距

    前言 对应一个曾经开发 Android 的人来说,没有这些基础属性简直令人发指,还是表喷这个,认真写代码 - - # 声明 欢迎转载,但请保留文章原始出处:) 博客园:http://www.cnblo ...

  8. iOS 设置UILabel 的内边距

    iOS 设置UILabel 的内边距 - (void)drawTextInRect:(CGRect)rect { UIEdgeInsets insets = {, , , }; [super draw ...

  9. 设置layui表格cell的内边距

    /*设置layui表格cell的内边距*/ .layui-table-cell { height: 50px !important; line-height: 50px !important; }

随机推荐

  1. 在NestJS 中添加对Stripe 的WebHook 验证

    在NestJS 中添加对Stripe 的WebHook 验证 背景介绍 Nest 是一个用于构建高效,可扩展的NodeJS 服务器端应用程序的框架.它使用渐进式JavaScript, 内置并完全支持T ...

  2. python批量修改图片名称

    import os class BatchRename(): def rename(self): # windows环境 """ os.rename() 方法用于命名文件 ...

  3. 使用adb如何批量给设备安装apk

    win系统 1.首先我们需要在本地建一个文件夹apks,然后把所要安装的apk放进去 2.打开dos窗口使用for循环进行安装即可(前提你的电脑已经连接上了设备,输入adb devices可查看) f ...

  4. jvm源码解读--18 Java的start()方法解读 以及 wait 和notify流程图

    drawwed by 张艳涛 and get info from openjdk8 还有一个图

  5. 【阅读笔记】Java核心技术卷一 #1.Chapter3

    3 Java的基本程序设计结构 3.1 一个简单的 Java 应用程序(略) 3.2 注释(略) 3.3 数据类型 8种基本类型 byte,short,int,long float,double ch ...

  6. <textarea></textarea>标签的placeholder属性不生效问题

    <textarea></textarea>标签的placeholder属性不生效问题   1.在用到<textarea></textarea>标签时,设 ...

  7. SQL注入之二次,加解密,DNS等注入

    #sql注入之二次注入 1.注入原理 二次注入可以理解为,构造恶意数据存储在数据库后,恶意数据被读取并进入到了SQL查询语句所导致的注入.恶意数据插入到数据库时被处理的数据又被还原并存储在数据库中,当 ...

  8. Tomcat7+ 弱口令 && 后台getshell漏洞

    打开tomcat管理页面http://192.168.49.2:8080/manager/html,输入弱密码tomcat:tomcat,即可访问后台 先将jsp大马压缩为zip,再将zip后缀改名为 ...

  9. 🏆(不要错过!)【CI/CD技术专题】「Jenkins实战系列」(3)Jenkinsfile+DockerFile实现自动部署

    每日一句 没有人会因学问而成为智者.学问或许能由勤奋得来,而机智与智慧却有懒于天赋. 前提概要 Jenkins下用DockerFile自动部署Java项目,项目的部署放心推向容器化时代机制. 本节需要 ...

  10. 遗传算法 TSP(Python代码)

    该代码是本人根据B站up主侯昶曦的代码所修改的. 原代码github地址:https://github.com/Houchangxi/heuristic-algorithm/blob/master/T ...