Swift- 设置 UILabel 内边距
摘要
拿来即用短时间效率虽然挺高的,但是拿来的东西没有消化一次,就无法得心应手的使用它。
这次的探索思路就是,查询官方文档,设置不同的值测试单个方法中参数的变化,之后测试两个方法的执行顺序,处理的思路,最后思考总结。
在总结方法的处理逻辑时,使用伪代码的方式梳理方法的执行思路。避免解释文本太多,增加理解的成本。
最近在学习小程序开发,接触到 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方法,不管设置还是不设置内边距也总是被调用,会不会影响性能啊?
这里提供两个方法解决:
可操作性的,就是尽量考虑需求,在不得不用的时候再使用
心理安慰性质的,那就是放下。细想一下,这两个方法都是重写的方法,重写的本质是什么?那就是不执行自己的方法,执行重写的方法。换句话说,就算系统不走重写的方法,也要走自己的方法。而这些代码对性能的影响,不值一提。
新发现
突然之间,有没有发现,咱们似乎也明白了,为什么UILabel不用固定它的height,它就可以自己确定高度,完全展示 text文本?你想.你细想...
Swift- 设置 UILabel 内边距的更多相关文章
- 可以简易设置文字内边距的EdgeInsetsLabel
可以简易设置文字内边距的EdgeInsetsLabel 最终效果: 源码: EdgeInsetsLabel.h 与 EdgeInsetsLabel.m // // EdgeInsetsLabel.h ...
- W3School-CSS 内边距 (padding) 实例
CSS 内边距 (padding) 实例 CSS 实例 CSS 背景实例 CSS 文本实例 CSS 字体(font)实例 CSS 边框(border)实例 CSS 外边距 (margin) 实例 CS ...
- CSS.03 -- 浏览器行高、字体;盒子模型--边框、内边距、外边距
如果此时你也在自学中,请使用 FireWorks CS6 进行切图测距等,百度一下吧~ Fireworks的基本使用 新建文件 ctrl+n 打开文件 ctrl+o 调出和隐藏标尺 ctrl+r ...
- 谈谈tableView的重要属性内边距
全屏穿透效果需要做到两点 tableView的可视范围占据整个父控件(或者屏幕)--设置contentsize滚动范围. 所有的cell都可以被看到,也就是说tableView中的cell不会被导航栏 ...
- CSS 内边距 (padding) 实例
CSS 内边距 (padding) 实例元素的内边距在边框和内容区之间.控制该区域最简单的属性是 padding 属性. CSS padding 属性定义元素边框与元素内容之间的空白区域.CSS 内边 ...
- CSS 内边距 padding 属性
CSS padding 属性定义元素边框与元素内容之间的空白区域. ㈠padding(填充) ⑴当元素的 padding(填充)内边距被清除时,所释放的区域将会受到元素背景颜色的填充. ⑵单独使用 p ...
- 【Swift】UILabel 设置内边距
前言 对应一个曾经开发 Android 的人来说,没有这些基础属性简直令人发指,还是表喷这个,认真写代码 - - # 声明 欢迎转载,但请保留文章原始出处:) 博客园:http://www.cnblo ...
- iOS 设置UILabel 的内边距
iOS 设置UILabel 的内边距 - (void)drawTextInRect:(CGRect)rect { UIEdgeInsets insets = {, , , }; [super draw ...
- 设置layui表格cell的内边距
/*设置layui表格cell的内边距*/ .layui-table-cell { height: 50px !important; line-height: 50px !important; }
随机推荐
- Delimiter must not be alphanumeric or backslash php报错原因
昨天写了一个小程序,其中用到了正则表达式去匹配内容. php源代码如下: preg_match("\b(\w+)\b\s+\1\b",$match): 此报错警告的中文意思是 ...
- mysql常用sql语法
一.创建主键的三种方式 1. CREATE TABLE user( uid INT PRIMARY KEY, uname VARCHAR(10), address VARCHAR(20) ) 2. C ...
- C#计算复利方法
复利即是指利滚知利 如存入1000,年利息回0.003,存了答10年,则调用fl(0.003,1000,10); double fl(double rate,double cash,int times ...
- vue知识点----element UI+vue关于日期范围选择的操作,picker-options属性的使用
需求场景如下: 指定起止日期,后选的将会受到先选的限制 不同的日期选择器,不过也存在关联关系 实现方法不难,利用了 change 事件,动态改变 picker-options 中的 disableDa ...
- kivy中文编程指南
Kivy中文编程指南,由网友翻译后,我整理目录及页面形式,便了浏览查阅. 点击下载
- mysql zip 安装
第一步下载mysql.zip https://dev.mysql.com/downloads/mysql/5.7.html#downloads 第二步:解压文件后在其目录下, 新建 my.ini ...
- azure bash: kubectl: command not found
[root@***]# az aks install-cliDownloading client to "/usr/local/bin/kubectl" from "ht ...
- i春秋CTF-web-upload
------------恢复内容开始------------ 记一道文件上传的题目. 题目告诉我们随意上传,第一想到的当然给他上传一个木马文件然后蚁剑拿shell,上传之后可以在源码里查看我们上传的文 ...
- 字节跳动上传了一份“面试官版Android面试小册”,不讲一句废话,全是精华
前言 金三银四马上就到了,很多粉丝朋友私信希望我出一篇面试专题或者分享面试相关的笔记来学习,这不今天就给大家安排上了?(都是干货,错过就是亏.) 下面的面试笔记都是精心整理好免费分享给大家的,希望新朋 ...
- MySQL-11-存储引擎
存储引擎简单介绍 存储引擎:相当于Linux文件系统,只不过比文件系统强大 功能 数据读写 数据安全和一致性 提高性能 热备份 自动故障恢复 高可用方面支持 存储引擎种类 InnoDB MyISAM ...