百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

Swift-设置 UILabel 内边距(swiftui frame)

bigegpt 2025-03-26 10:03 15 浏览

摘要

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

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

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

最近在学习小程序开发,接触到 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文本?你想.你细想...

相关推荐

Linux gron 命令使用详解(linux gminer)

简介gron是一个独特的命令行工具,用于将JSON数据转换为离散的、易于grep处理的赋值语句格式。它的名字来源于"grepableon"或"grepable...

【Linux】——从0到1的学习,让你熟练掌握,带你玩转Linu

学习Linux并掌握Java环境配置及SpringBoot项目部署是一个系统化的过程,以下是从零开始的详细指南,帮助你逐步掌握这些技能。一、Linux基础入门1.安装Linux系统选择发行版:推荐...

Linux常用的shell命令汇总(linux中shell的作用)

本文介绍Linux系统下常用的系统级命令,包括软硬件查看、修改命令,有CPU、内存、硬盘、网络、系统管理等命令。说明命令是在Centos6.464位的虚拟机系统进行测试的。本文介绍的命令都会在此C...

零成本搭建个人加密文件保险柜(适用于 Win11 和 Linux)

不依赖收费软件操作简单,小白也能跟着做支持双系统,跨平台使用实现数据加密、防删除、防泄露内容通俗无技术门槛,秒懂秒用使用工具简介我们将使用两个核心工具:工具名用途系统支持Veracrypt创建加密虚...

如何在 Linux 中使用 Gzip 命令?(linux怎么用gzip命令)

gzip(GNUzip)是Linux系统中一个开源的压缩工具,用于压缩和解压缩文件。它基于DEFLATE算法,广泛应用于文件压缩、备份和数据传输。gzip生成的文件通常带有.gz后缀,压缩效率...

Linux 必备的20个核心知识点(linux内核知识点)

学习和使用Linux所必备的20个核心知识点。这些知识点涵盖了从基础操作到系统管理和网络概念,是构建扎实Linux技能的基础。Linux必备的20个知识点1.Linux文件系统层级标...

谷歌 ChromeOS 已支持 7z、iso、tar 文件格式

IT之家6月21日消息,谷歌ChromeOS在管理文件方面进行了改进,新增了对7z、iso和tar等格式的支持。从5月的ChromeOS101更新开始,ChromeOS...

如何在 Linux 中提取 Tar Bz2 文件?

在深入解压方法之前,我们先来了解.tar.bz2文件的本质。.tar.bz2是一种组合文件格式,包含两个步骤:Tar(TapeArchive):tar是一种归档工具,用于将多个文件或目录打包...

如何在 CentOS 7/8 上安装 Kitematic Docker 管理器

Kitematic是一款流行的Docker图形界面管理平台,适用于Ubuntu、macOS和Windows操作系统。然而,其他发行版(如CentOS、OpenSUSE、Fedora、R...

Nacos3.0重磅来袭!全面拥抱AI,单机及集群模式安装详细教程!

之前和大家分享过JDK17的多版本管理及详细安装过程,然后在项目升级完jdk17后又发现之前的注册和配置中心nacos又用不了,原因是之前的nacos1.3版本的,版本太老了,已经无法适配当前新的JD...

爬虫搞崩网站后,程序员自制“Zip炸弹”反击,6刀服务器成功扛住4.6万请求

在这个爬虫横行的时代,越来越多开发者深受其害:有人怒斥OpenAI的爬虫疯狂“偷”数据,7人团队十年心血的网站一夜崩溃;也有人被爬虫逼到极限,最后只好封掉整个巴西的访问才勉强止血。但本文作者却走...

Ubuntu 操作系统常用命令详解(ubuntu必学的60个命令)

UbuntuLinux是一款流行的开源操作系统,广泛应用于服务器、开发、学习等场景。命令行是Ubuntu的灵魂,也是高效、稳定管理系统的利器。本文按照各大常用领域,详细总结Ubuntu必学...

Linux面板8.0.54 测试版-已上线(linux主机面板)

Linux面板8.0.54测试版【增加】[网站]Java项目新增刷新列表按钮【增加】[网站]PHP项目-Apache-服务新增守护进程功能【增加】[网站]Python项目创建/删除网站时新增同时创建...

开源三剑客——构建私有云世界的基石

公共云原生的浪潮正在席卷这个世界,亚马逊AWS、谷歌GCP和微软的Azure年收入增长超过了30%,越来越多的公司和个人开始将自己的服务部署到云环境中,大型数据中心的规模经济带来了成本的降低,可以在保...

2.2k star,一款业界领先的私有云+在线文档管理系统

简介kodbox可道云(原KodExplorer)是业内领先的企业私有云和在线文档管理系统,为个人网站、企业私有云部署、网络存储、在线文档管理、在线办公等提供安全可控,简便易用、可高度定制的私有云产品...