Swift设置UILabel内边距的实例代码

目录
  • 摘要
  • textRect 的作用
  • drawText 的作用
  • 优化
  • 扩展
  • 新发现
  • 总结

摘要

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

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

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

最近在学习小程序开发,接触到 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内边距的文章就介绍到这了,更多相关Swift设置UILabel内边距内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Swift设置UILabel内边距的实例代码

    目录 摘要 textRect 的作用 drawText 的作用 优化 扩展 新发现 总结 摘要 拿来即用短时间效率虽然挺高的,但是拿来的东西没有消化一次,就无法得心应手的使用它. 这次的探索思路就是,查询官方文档,设置不同的值测试单个方法中参数的变化,之后测试两个方法的执行顺序,处理的思路,最后思考总结. 在总结方法的处理逻辑时,使用伪代码的方式梳理方法的执行思路.避免解释文本太多,增加理解的成本. 最近在学习小程序开发,接触到 flex 方式布局,很喜欢这种快速和方便的方式.所以当遇到一个页面

  • 设置cookie指定时间失效(实例代码)

    实例如下: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <script type="text/javascript"> // 设置cookie在当天指定时间点过期并提示 function setCookie(name,value,Deadline){ // 获取当前日期对象 var curD

  • Python操作Redis之设置key的过期时间实例代码

    Expire 命令用于设置 key 的过期时间.key 过期后将不再可用. r.set('2', '4028b2883d3f5a8b013d57228d760a93') #成功就返回True 失败就返回False,下面的20表示是20秒 print r.expire('2',20) #如果时间没事失效我们能得到键为2的值,否者是None print r.get('2') 对于一个已经存在的key,我们可以设置其过期时间,到了那个时间后,当你再去访问时,key就不存在了 有两种方式可以设置过期时间

  • javascript cookies 设置、读取、删除实例代码

    刚整理了一些关于javascript cookies操作的文章,发现这篇文章也不错,推荐大家一起参考,选择需要的,不足的地方主要是对路径的设置,喜欢的朋友可以结合下. 复制代码 代码如下: <script> function SetCookie(name,value)//两个参数,一个是cookie的名子,一个是值 { var Days = 30; //此 cookie 将被保存 30 天 var exp = new Date(); //new Date("December 31,

  • Swift Self详解及简单实例代码

    Swift中Self的使用 用于消除访问属性,调用方法时所产生的歧义. 当函数的参数名和自身的属性名同名时,例如: /* 使用self指明被访问的是自身属性还是参数 */ class AClass { var greeting: String init(greeting: String) { // 使用self区分属性和参数 self.greeting = greeting } } 在便利构造函数中调用自身的指定构造函数时,例如: convenience init() { /* 必须使用self

  • echarts地图设置背景图片及海岸线实例代码

    目录 1.地图设置背景图片 2.地图外部多层轮廓线 3.地图海岸线 4.地图中高亮显示有数据的城市 5.滚动高亮轮播 总结 1.地图设置背景图片 // data domImg: require('@/assets/images/largescreen/nation/map_bg.png'), // js 渲染地图之前 var domImg = document.createElement("img"); domImg.style.height = domImg.height = dom

  • Swift UILable 设置内边距实例代码

    前言 对应一个曾经开发 Android 的人来说,没有这些基础属性简直令人发指,还是表喷这个,认真写代码 - - #  正文 代码实现: class UILabelPadding : UILabel { private var padding = UIEdgeInsetsZero @IBInspectable var paddingLeft: CGFloat { get { return padding.left } set { padding.left = newValue } } @IBIn

  • Swift仿微信语音通话最小化时后的效果实例代码

    前言 最近碰到个需求,需要仿微信语音通话缩小化后,保持界面最上层有一个悬浮的小View可以一点击就把刚刚缩放掉的界面再放回来,其实本质就是创造了一个新的Window,在这个window上创建了一个rootController并展示他,缩小化时是把controller dismiss掉了,再次点击那个小View之后把这个controller再展示出来便可以了.同理微信小程序其实也是在一个新的Window中做了一套新的逻辑.随着现在手机性能的提升,多Window同时存在并不会造成严重卡顿,而衍生出来

  • AngularJS点击添加样式、点击变色设置的实例代码

    本文介绍了AngularJS点击添加样式.点击变色设置的实例代码,分享给大家,具体如下: 首先解释需求是这样的,有个列表,当你点击哪一行时,哪一行背景变成灰色,在JQ中,大家都知道,这是非常容易的,加一个addClass就行了,那么AngularJS如何实现呢? 下面我们看代码部分 <!doctype html> <html ng-app="a2_11"> <head> <title>添加元素样式</title> <sc

  • iOS中关于音乐锁屏控制音乐(锁屏信息设置)的实例代码

    废话不多说了,直接给大家贴代码了,具体代码如下所示: <pre name="code" class="objc">appDelegate里面加入如下代码获取后台播放权限</pre><pre name="code" class="objc">- (void)setAudioBackstagePlay{ AVAudioSession *audioSession = [AVAudioSession

随机推荐