在标记中创建自定义表格视图单元格

一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / Java 学习路线 / 一对一提问 / 学习打卡/ 赠书活动

目前,正在 星球 内带小伙伴们做第一个项目:全栈前后端分离博客项目,采用技术栈 Spring Boot + Mybatis Plus + Vue 3.x + Vite 4手把手,前端 + 后端全栈开发,从 0 到 1 讲解每个功能点开发步骤,1v1 答疑,陪伴式直到项目上线,目前已更新了 204 小节,累计 32w+ 字,讲解图:1416 张,还在持续爆肝中,后续还会上新更多项目,目标是将 Java 领域典型的项目都整上,如秒杀系统、在线商城、IM 即时通讯、权限管理等等,已有 870+ 小伙伴加入,欢迎点击围观

传统上,实现自定义表格视图单元格一直是 iOS 开发中更具挑战性的方面之一。在早期版本的操作系统中,开发人员必须手动计算单元格大小和定位子视图,这是一个耗时且容易出错的过程。

自从引入布局约束和自调整单元格以来,这个过程变得更加简单,但是 MarkupKit 允许开发人员完全在标记中定义单元格的结构,从而使它变得更加容易。 LMColumnView LMRowView 等布局视图可用于自动定位单元格的子视图并响应内容和方向更改,让单元格类本身仅负责提供单元格的行为。

例如,以下屏幕截图显示了一个表格视图,其中显示了模拟药房搜索结果的列表:




















表视图的内容由包含搜索结果的 JSON 文档定义。在示例应用程序中,这些结果是静态的。在实际的应用程序中,它们可能是由某种网络服务动态生成的:


 [
    {
      "name": "Green Cross Pharmacy",
      "address1": "393 Hanover Street",
      "city": "Boston",
      "state": "MA",
      "zipCode": "02108",
      "latitude": 42.365142822266,
      "longitude": -71.052879333496,
      "phone": "6172273728",
      "email": "pharmacy@greencross.com",
      "fax": "6177420001",
      "distance": 0.15821025961609
    },
    {
      "name": "CVS",
      "address1": "263 Washington Street",
      "city": "Boston",
      "state": "MA",
      "zipCode": "02108",
      "latitude": 42.357696533203,
      "longitude": -71.058090209961,
      "phone": "6177427035",
      "email": "store01@cvs.com",
      "fax": "6177420001",
      "distance": 0.42181156854188
    },
    {
      "name": "Walgreens",
      "address1": "70 Summer Street",
      "city": "Boston",
      "state": "MA",
      "zipCode": "02108",
      "latitude": 42.354225158691,
      "longitude": -71.05818939209,
      "phone": "6172657488",
      "email": "store04@walgreens.com",
      "fax": "6177420001",
      "distance": 0.64790764418076
    },
...

]

示例表视图控制器在 viewDidLoad 中加载模拟结果数据并将其存储在名为 pharmacies 的实例变量中。它还将表视图的 estimatedRowHeight 属性设置为 2。将此属性设置为非零值对于启用表视图的自调整单元格行为是必要的:


 [
    {
      "name": "Green Cross Pharmacy",
      "address1": "393 Hanover Street",
      "city": "Boston",
      "state": "MA",
      "zipCode": "02108",
      "latitude": 42.365142822266,
      "longitude": -71.052879333496,
      "phone": "6172273728",
      "email": "pharmacy@greencross.com",
      "fax": "6177420001",
      "distance": 0.15821025961609
    },
    {
      "name": "CVS",
      "address1": "263 Washington Street",
      "city": "Boston",
      "state": "MA",
      "zipCode": "02108",
      "latitude": 42.357696533203,
      "longitude": -71.058090209961,
      "phone": "6177427035",
      "email": "store01@cvs.com",
      "fax": "6177420001",
      "distance": 0.42181156854188
    },
    {
      "name": "Walgreens",
      "address1": "70 Summer Street",
      "city": "Boston",
      "state": "MA",
      "zipCode": "02108",
      "latitude": 42.354225158691,
      "longitude": -71.05818939209,
      "phone": "6172657488",
      "email": "store04@walgreens.com",
      "fax": "6177420001",
      "distance": 0.64790764418076
    },
...

]

自定义单元类本身定义如下:


 [
    {
      "name": "Green Cross Pharmacy",
      "address1": "393 Hanover Street",
      "city": "Boston",
      "state": "MA",
      "zipCode": "02108",
      "latitude": 42.365142822266,
      "longitude": -71.052879333496,
      "phone": "6172273728",
      "email": "pharmacy@greencross.com",
      "fax": "6177420001",
      "distance": 0.15821025961609
    },
    {
      "name": "CVS",
      "address1": "263 Washington Street",
      "city": "Boston",
      "state": "MA",
      "zipCode": "02108",
      "latitude": 42.357696533203,
      "longitude": -71.058090209961,
      "phone": "6177427035",
      "email": "store01@cvs.com",
      "fax": "6177420001",
      "distance": 0.42181156854188
    },
    {
      "name": "Walgreens",
      "address1": "70 Summer Street",
      "city": "Boston",
      "state": "MA",
      "zipCode": "02108",
      "latitude": 42.354225158691,
      "longitude": -71.05818939209,
      "phone": "6172657488",
      "email": "store04@walgreens.com",
      "fax": "6177420001",
      "distance": 0.64790764418076
    },
...

]

该类扩展了 LMTableViewCell ,它是 UITableViewCell 的一个子类,有助于在标记中定义自定义单元格内容,并为将在标记文档中定义的视图声明多个出口。在 initWithStyle:reuseIdentifier: 中,它从名为 PharmacyCell.xml 的 文档中加载自定义视图层次结构。 initWithCoder: 方法虽然未被使用,但却是 Swift 所必需的。不需要其他逻辑。

PharmacyCell.xml 定义如下:


 [
    {
      "name": "Green Cross Pharmacy",
      "address1": "393 Hanover Street",
      "city": "Boston",
      "state": "MA",
      "zipCode": "02108",
      "latitude": 42.365142822266,
      "longitude": -71.052879333496,
      "phone": "6172273728",
      "email": "pharmacy@greencross.com",
      "fax": "6177420001",
      "distance": 0.15821025961609
    },
    {
      "name": "CVS",
      "address1": "263 Washington Street",
      "city": "Boston",
      "state": "MA",
      "zipCode": "02108",
      "latitude": 42.357696533203,
      "longitude": -71.058090209961,
      "phone": "6177427035",
      "email": "store01@cvs.com",
      "fax": "6177420001",
      "distance": 0.42181156854188
    },
    {
      "name": "Walgreens",
      "address1": "70 Summer Street",
      "city": "Boston",
      "state": "MA",
      "zipCode": "02108",
      "latitude": 42.354225158691,
      "longitude": -71.05818939209,
      "phone": "6172657488",
      "email": "store04@walgreens.com",
      "fax": "6177420001",
      "distance": 0.64790764418076
    },
...

]

根元素是 LMColumnView 的一个实例,它是一种自动将其子视图排列在垂直线上的布局视图。 “spacing”属性指定列视图应在子视图之间留出 4 个像素的间隙,“layoutMarginBottom”属性指定最后一个子视图与单元格底部之间应留有 8 个像素的间隙。

该列的第一个子视图是 LMRowView 的一个实例,它是一个将其子视图排列在水平线上的布局视图。该行的子视图将与基线对齐,并且它们之间有 4 个像素的间隙。它包含两个 UILabel 实例,一个用于显示药房的名称,另一个用于显示从用户当前位置到药房的距离。两个标签都被分配了 ID 值,这些值将它们关联的视图实例映射到文档所有者(在本例中为自定义单元格类)声明的名称相似的出口。标签的样式也分别使用当前系统字体显示为 16 磅粗体和 14 磅普通文本。

另一个标签是为药房的邮寄地址创建的,另一个列视图包含药房电话号码、传真号码和电子邮件地址的图标和标签。这些标签还分配了 ID,将它们与单元类定义的出口相关联。电话、传真和电子邮件行的标签被分配了一个“权重”值 1,这告诉行视图将其未分配空间的 100% 分配给标签;这确保图标将出现在左侧并且标签将填充行中的剩余空间。

表视图控制器覆盖 tableView:cellForRowAtIndexPath: 为搜索结果中的每一行生成 PharmacyCell 实例。它从 pharmacies 数组中检索表示行的字典实例,并使用单元格的出口填充单元格。它对从 JSON 文档中检索到的原始数据执行一些格式化,以使单元格的内容更具可读性:


 [
    {
      "name": "Green Cross Pharmacy",
      "address1": "393 Hanover Street",
      "city": "Boston",
      "state": "MA",
      "zipCode": "02108",
      "latitude": 42.365142822266,
      "longitude": -71.052879333496,
      "phone": "6172273728",
      "email": "pharmacy@greencross.com",
      "fax": "6177420001",
      "distance": 0.15821025961609
    },
    {
      "name": "CVS",
      "address1": "263 Washington Street",
      "city": "Boston",
      "state": "MA",
      "zipCode": "02108",
      "latitude": 42.357696533203,
      "longitude": -71.058090209961,
      "phone": "6177427035",
      "email": "store01@cvs.com",
      "fax": "6177420001",
      "distance": 0.42181156854188
    },
    {
      "name": "Walgreens",
      "address1": "70 Summer Street",
      "city": "Boston",
      "state": "MA",
      "zipCode": "02108",
      "latitude": 42.354225158691,
      "longitude": -71.05818939209,
      "phone": "6172657488",
      "email": "store04@walgreens.com",
      "fax": "6177420001",
      "distance": 0.64790764418076
    },
...

]

PhoneNumberFormatter 类定义如下:


 [
    {
      "name": "Green Cross Pharmacy",
      "address1": "393 Hanover Street",
      "city": "Boston",
      "state": "MA",
      "zipCode": "02108",
      "latitude": 42.365142822266,
      "longitude": -71.052879333496,
      "phone": "6172273728",
      "email": "pharmacy@greencross.com",
      "fax": "6177420001",
      "distance": 0.15821025961609
    },
    {
      "name": "CVS",
      "address1": "263 Washington Street",
      "city": "Boston",
      "state": "MA",
      "zipCode": "02108",
      "latitude": 42.357696533203,
      "longitude": -71.058090209961,
      "phone": "6177427035",
      "email": "store01@cvs.com",
      "fax": "6177420001",
      "distance": 0.42181156854188
    },
    {
      "name": "Walgreens",
      "address1": "70 Summer Street",
      "city": "Boston",
      "state": "MA",
      "zipCode": "02108",
      "latitude": 42.354225158691,
      "longitude": -71.05818939209,
      "phone": "6172657488",
      "email": "store04@walgreens.com",
      "fax": "6177420001",
      "distance": 0.64790764418076
    },
...

]

因此,使用标记来布置单元格的内容可以显着简化创建自定义表格视图单元格的过程。随着应用程序需求的发展,它还可以轻松修改单元格的布局。