当前位置: 首页 > article >正文

UI学习—cell的复用和自定义cell

前言

  • Nib是什么?

Nib就是.xib文件:一个可视化的UI界面文件,它记录了一个UI组件(例如一个表格单元格Cell)的界面布局信息,可以在interfaceBuilder中创建

[UINib nibWithNibName:@"CustomCell" bundle:nil]

这段代码的意思就是加载一个名叫CustomCell.xib的XIB文件,把它变成UINib对象么,准备好以后注册给其他对象使用

参数介绍 :

1.@“CustomCell”:XIB文件名,不可以带.xib后缀

  1. bundle:nil :默认从主包加载

介绍

cell复用和自定义cell是在开发iOS应用时常见的优化技巧和定制需求,cell复用是UITableView或UIColletionView的一个重要‼️的优化机制。当用户滚动这些视图时,只有少量可见的cell会被创建和显示出来,对于那些不可见的cell,徐系统会将他们缓存起来以备将来使用。当用户在滚动屏幕的时候,屏幕上的cell只是所有数据的一小部分,当某个cell滚动出屏幕时,系统会将其放入一个队列中等待复用,当需要显示新的cell时,系统会首先检查这个队列,看是否有可以复用的cell,如果有就直接使用,如果没有才会创建新的cell。在实现cell的复用时,需要给cell设定不同的复用标识符(reuse identifier),然后在需要新的cell时,使用这个标识符去请求,如果队列中有可复用的cell,系统就会返回一个,否则就会创建新的cell,标识符的设定,使得我们可以为不同类型的cell设定不同的复用标识符,从而在同一个表视图或者集合视图中使用多种类型的cell。

复用原理

当创建UITableView并加载数据时,系统会实现如下操作

  1. 创建缓存结构:

    1. 一个字典:用于缓存cell的类与标识符的关系
    2. 一个数组:记录每个section的可见行信息
    3. 一个可变集合mutableSet:专门存放可以复用的cell
  2. 加载首屏cell(n + 1)个

    1. 他会调用
    [dataSource tableView:cellForRowAtIndexPath:]
    
    1. 并通过
    [tableView dequeueReusableCellWithIdentifier:@"MyCellID"]
    

    去查看是否有可复用的cell?

  3. cell滚出屏幕时,系统就会把他放进reuse pool中,而不是释放掉

  4. 向下滚动时,取出reuse pool 的cell

UITableView中cell复用方式

手动(非注册)

  • 什么是非注册类型的?

非注册类型 = 没有使用registerClass:或registerNib:来注册cell,而是手动判断并创建的方式

  • 使用方式
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {static NSString *identifier = @"MyCellID";// 从复用池中获取UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];// 如果没有可复用的 cell,则创建一个新的if (!cell) {cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];// 只初始化一次的配置可以写在这里cell.selectionStyle = UITableViewCellSelectionStyleNone;}// 每次都要重新配置内容cell.textLabel.text = [NSString stringWithFormat:@"Row %ld", indexPath.row];return cell;
}
  • 原理分析

UITableview会从内部的复用池寻找标识符为identifier的cell,如果没有可复用的cell,就返回nil,此时需要手动创建一个新的并指定相同的reuseIdentifier,系统会在滚动后自动将cell回收到复用池中

  • 使用场景推荐
    • 完全动态的cell类型
NSString *identifier = [NSString stringWithFormat:@"Section_%ld", indexPath.section];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) {cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier];
}

目的:每个section使用一个不同的复用标识符

自动(注册类型)

  • 什么是注册类型?

注册类型 = 提前告诉UITableView或UICollectionView:会使用哪一种cell(类或nib)来复用

注册后,系统会在你调用 dequeueReusableCellWithIdentifier:forIndexPath: 时,自动为你创建或复用cell,不再需要手动写 if (!cell)

  • 注册方式
  1. 注册类
[tableView registerClass:[MyCustomCell class] forCellReuseIdentifier:@"MyCellID"];

告诉系统会使用MyCustomCell这个类作为cell,reuseIdentifier是“MyCellID”

这个类必须是UITableViewCell的子类,且支持用init方法初始化,纯代码模式,不依赖.xib文件

适用于cell布局不复杂,可以通过AutoLayout或frame代码快速搭建,不需要使用Interface Builder

  1. 注册XIB(nib文件方式)
UINib *nib = [UINib nibWithNibName:@"MyCustomCell" bundle:nil];
[tableView registerNib:nib forCellReuseIdentifier:@"MyCellID"];

告诉系统会使用一个名为MyCustomCell.xib的nib文件创建cell

nib里要设置cell的class是自定义类的UITableViewCell子类

  • 如何使用已注册的cell?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {MyCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyCellID" forIndexPath:indexPath];// 配置 cell 的内容cell.titleLabel.text = self.dataArray[indexPath.row];return cell;
}

自定义cell的实现

如果要实现自定义cell需要实现两个协议

UItableViewDelegate和UITableViewDataSource

前者:

//即将显示道屏幕上时调用
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;
//当某个section的Header即将显示时调用
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section API_AVAILABLE(ios(6.0));
//某个 section 的 Footer 即将显示时调用
- (void)tableView:(UITableView *)tableView willDisplayFooterView:(UIView *)view forSection:(NSInteger)section API_AVAILABLE(ios(6.0));
//当某个cell即将滑出屏幕并结束显示时调用
- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath*)indexPath API_AVAILABLE(ios(6.0));
//某个header滑出屏幕后调用
- (void)tableView:(UITableView *)tableView didEndDisplayingHeaderView:(UIView *)view forSection:(NSInteger)section API_AVAILABLE(ios(6.0));
//某个footer滑出屏幕后调用
- (void)tableView:(UITableView *)tableView didEndDisplayingFooterView:(UIView *)view forSection:(NSInteger)section API_AVAILABLE(ios(6.0));
//返回某一行的高度
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
//返回每个section的header高度
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;
//设置每个section的footer高度
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section;

后者:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;// Row display. Implementers should *always* try to reuse cells by setting each cell's reuseIdentifier and querying for available reusable cells with dequeueReusableCellWithIdentifier:
// Cell gets various attributes set automatically based on table (separators) and data source (accessory views, editing controls)- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;

使用原因:

  1. 个性化设计需求,当系统提供的单元格样式无法满足应用的设计需求时,就需要通过自定义单元格来实现特定的界面和布局
  2. 复杂的数据展示:如果需要在单元格中显示复杂的数据结构(如图文混排、动态控件集合等),使用自定义单元格可以更灵活的控制数据的展示方式
  3. 优化性能:当列表视图中需要展示的单元格类型非常多样或者数据加载非常复杂时,通过精心设计的自定义单元格可以有效的提高滚动和渲染的性能

在自定义cell时,我们需要新建一个UITableViewCell类,在这个类的h文件中添加我们所需要的相关控件,在m文件中重写初始化initWithStyle:reuseldenifier:方法,在该方法中,首先使用父类的init方法初始化,以创建一个合法的cell,然后手动为该self的各个属性赋值,最后返回self即可

注意:在需要将自定义控价先添加道self.contentView上,这个contentView就是cell的子视图,是内容视图

  • 自定义cell
#import <UIKit/UIKit.h>NS_ASSUME_NONNULL_BEGIN@interface MyCustomCell : UITableViewCell
@property(nonatomic, strong) UILabel* titleLabel;
@endNS_ASSUME_NONNULL_END
#import "MyCustomCell.h"@implementation MyCustomCell//这是UITableView的指定初始化方法
/*参数讲解参数一:cell的样式参数二:用于cell的复用机制,标记这个cell的身份*/
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {//调用父类的UITableView的构造方法,初始化基础内容,必须写,否则无法获得一个合法的cell实例self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];if (self) {self.titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(15, 10, 300, 30)];self.titleLabel.textColor = [UIColor orangeColor];//contentView是UITbableCell内部的容器视图,应该把所有UI元素加到它上面,而不是直接加到cell本身[self.contentView addSubview:self.titleLabel];}return self;
}- (void)awakeFromNib {[super awakeFromNib];// Initialization code
}- (void)setSelected:(BOOL)selected animated:(BOOL)animated {[super setSelected:selected animated:animated];// Configure the view for the selected state
}@end
  • 实现
#import "ViewController.h"
#import "MyCustomCell.h"@interface ViewController () <UITableViewDelegate, UITableViewDataSource>@property (nonatomic, strong) UITableView *tableView;@end@implementation ViewController
- (void)viewDidLoad {[super viewDidLoad];self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];self.tableView.delegate = self;self.tableView.dataSource = self;[self.tableView registerClass:[MyCustomCell class] forCellReuseIdentifier:@"MyCellID"];[self.view addSubview:self.tableView];
}- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {return 20;
}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {MyCustomCell* cell = [tableView dequeueReusableCellWithIdentifier:@"MyCellID"forIndexPath:indexPath];cell.titleLabel.text = [NSString stringWithFormat:@"Row:%ld",indexPath.row];return cell;;
}
@end
  • 在实现文件中实现一个layoutSubViews方法来设置各个空间的位置

相关文章:

UI学习—cell的复用和自定义cell

前言 Nib是什么&#xff1f; Nib就是.xib文件&#xff1a;一个可视化的UI界面文件&#xff0c;它记录了一个UI组件&#xff08;例如一个表格单元格Cell&#xff09;的界面布局信息&#xff0c;可以在interfaceBuilder中创建 [UINib nibWithNibName:"CustomCell" b…...

20250605使用boot-repair来恢复WIN10和ubuntu22.04.6双系统的启动

rootrootrootroot-X99-Turbo:~$ sudo apt-get install boot-repair rootrootrootroot-X99-Turbo:~$ sudo add-apt-repository ppa:yannubuntu/boot-repair rootrootrootroot-X99-Turbo:~$ sudo apt-get install boot-repair 20250605使用boot-repair来恢复WIN10和ubuntu22.04.6…...

网络安全面试题目(无答案)

一、渗透测试与漏洞挖掘 如何绕过WAF进行SQL注入&#xff1f;列举三种技术并解释原理。 答案要点&#xff1a; 分块传输编码&#xff08;Chunked Transfer&#xff09;绕过正则检测 畸形HTTP参数&#xff08;如参数污染、Unicode编码&#xff09; 利用WAF规则盲区&#xff08…...

JavaScript性能优化实战

### 1. 减少全局变量 JavaScript里&#xff0c;全局变量就像一个大杂烩&#xff0c;啥都往里扔&#xff0c;很容易出问题&#xff0c;还会影响性能。为啥呢&#xff1f;因为全局变量会被所有函数共享&#xff0c;查找起来特别费劲&#xff0c;就像在一个大仓库里找东西&#xf…...

接口安全SOAPOpenAPIRESTful分类特征导入项目联动检测

1 、 API 分类特征 SOAP - WSDL OpenApi - Swagger RESTful - /v1/api/ 2 、 API 常见漏洞 OWASP API Security TOP 10 2023 3 、 API 检测流程 接口发现&#xff0c;遵循分类&#xff0c;依赖语言&#xff0c; V1/V2 多版本等 Method &#xff1a;请求方法 攻击方…...

视频汇聚平台EasyCVR“明厨亮灶”方案筑牢旅游景区餐饮安全品质防线

一、背景分析​ 1&#xff09;政策监管刚性需求​&#xff1a;国家食品安全战略及 2024年《关于深化智慧城市发展的指导意见》要求构建智慧餐饮场景&#xff0c;推动数字化监管。多地将“AI明厨亮灶”纳入十四五规划考核&#xff0c;要求餐饮单位操作可视化并具备风险预警能力…...

sql server如何创建表导入excel的数据

在 SQL Server 中&#xff0c;可以通过几种方式将 Excel 数据导入到数据库表中。下面是一个完整的流程&#xff0c;包括如何创建表&#xff0c;以及将 Excel 数据导入该表的方法&#xff1a; ✅ 方法一&#xff1a;使用 SQL Server Management Studio (SSMS) 的导入向导&#x…...

仓库自动化搬运:自动叉车与AGV选型要点及核心技术解析

自动叉车与AGV均可实现自主作业&#xff0c;无需人工驾驶即可搬运托盘化货物。然而&#xff0c;这两种解决方案存在一些关键差异。 自动叉车与AGV的对比 自动叉车与AGV是截然不同的车辆&#xff0c;其差异主要源于原始设计&#xff1a; 自动叉车是制造商对传统手动叉车进行改…...

java UDP 模板

UDP&#xff08;User Datagram Protocol&#xff09;是一种无连接的传输层协议&#xff0c;在 Java 中可以使用 UDP 进行网络编程。理论上没有服务器客户端之分&#xff0c;实际上算是有的&#xff0c;以下是 Java 中 UDP 编程的基本步骤和示例代码&#xff1a; 服务器端 创建…...

【亲测有效】Mybatis-Plus更新字段为null

Mybatis-Plus更新字段为null 遇到问题 Mybatis-Plus更新的默认行为如下: Mybatis-Plus默认如果某个传入参数的字段为null, 默认不更新这个字段, 例如有个Double类型的字段, 当前数据库数据为10, 然后传参时当前字段为null, 实际上Mybatis-Plus是不会覆盖该字段为null的, 仍然…...

NLP学习路线图(二十五):注意力机制

在自然语言处理领域&#xff0c;序列模型一直扮演着核心角色。从早期的循环神经网络&#xff08;RNN&#xff09;到如今一统天下的Transformer模型&#xff0c;注意力机制&#xff08;Attention Mechanism&#xff09; 的引入堪称一场革命。它彻底改变了模型处理序列信息的方式…...

05 APP 自动化- Appium 单点触控 多点触控

文章目录 一、单点触控查看指针的指针位置实现手势密码&#xff1a; 二、多点触控 一、单点触控 查看指针的指针位置 方便查看手势密码-九宫格每个点的坐标 实现手势密码&#xff1a; 执行手势操作&#xff1a; 按压起点 -> 移动到下一点 -> 依次移动 -> 释放&am…...

MyBatis-Plus LambdaQuery 高级用法:JSON 路径查询与条件拼接的全场景解析

目录 1. 查询 JSON 字段中的特定值 2. 动态查询 JSON 字段中的值 3. 查询 JSON 数组中的值 4. 查询 JSON 字段中的嵌套对象 5. 结合其他条件查询 JSON 字段 6. 使用类型处理器简化 JSON 查询 6.1 创建自定义 JSON 类型处理器 6.2 在实体类中指定自定义类型处理器 示例…...

[AI绘画]sd学习记录(一)软件安装以及文生图界面初识、提示词写法

目录 目录一、安装软件二、文生图各部分模块 1. 下载新模型 & 画出第一张图2. 提示词输入 2.1 设置2.2 扩展模型2.3 扩展模型权重调整2.4 其他提示词输入2.5 负向提示词2.6 生成参考 3. 采样方法4. 噪声调度器5. 迭代步数6. 提示词引导系数 一、安装软件 软件安装&…...

SpringBoot(八) --- SpringBoot原理

目录 一、配置优先级 二、Bean的管理 1. Bean的作用域 2. 第三方Bean 三、SpringBoot原理 1. 起步依赖 2. 自动配置 3. 自动配置原理分析 3.1 源码解析 3.2 Conditional 一、配置优先级 SpringBoot项目当中支持三类配置文件&#xff1a; application.properties a…...

SpringBoot自动化部署全攻略:CI/CD高效实践与避坑指南

SpringBoot自动化部署全攻略:CI/CD高效实践与避坑指南 🚀 一、现代化部署方案选型对比 1. 主流CI/CD工具对比 工具优势适用场景Jenkins插件丰富、可扩展性强复杂流水线、混合云环境GitHub Actions与GitHub深度集成、易用GitHub项目、中小团队GitLab CI/CD一体化平台、内置…...

idea json生成实体类

在IntelliJ IDEA中&#xff0c;可以通过安装GsonFormat或GsonFormatPlus插件快速生成Java实体类‌。具体操作流程包括安装插件、创建空类后使用快捷键调出生成界面&#xff0c;输入JSON数据即可自动生成对应字段和结构。‌‌ 一、操作流程与工具选择‌ ‌1、插件安装‌ 在ID…...

C# 类和继承(抽象成员)

抽象成员 抽象成员是指设计为被覆写的函数成员。抽象成员有以下特征。 必须是一个函数成员。也就是说&#xff0c;字段和常量不能为抽象成员。必须用abstract修饰符标记。不能有实现代码块。抽象成员的代码用分号表示。 例如&#xff0c;下面取自一个类定义的代码声明了两个抽…...

gitlab rss订阅失败

问题&#xff1a;gitlab rss订阅失败 处理&#xff1a;http://gitlab.com/dashboard/projects.atom?feed_tokenXXXXXXX 这个XXX要改成用户设置里的Feed令牌 推荐本地rss订阅器&#xff1a;GitHub - yang991178/fluent-reader: Modern desktop RSS reader built with Electro…...

鸿蒙仓颉语言开发实战教程:商城登录页

听说Pura80要来了&#xff1f;感觉华为的新品像下饺子一样&#xff0c;让人目不暇接&#xff0c;每隔几天就有发布会看&#xff0c;真不错呀。 节后第一天&#xff0c;为了缓解大家假期的疲惫&#xff0c;咱们今天做点简单的内容&#xff0c;就是商城的登录页面。 其实这一次分…...

JavaScript 数组与流程控制:从基础操作到实战应用

在 JavaScript 编程的世界里&#xff0c;数组是一种极为重要的数据结构&#xff0c;它就像是一个有序的 “收纳盒”&#xff0c;能够将多个值整齐地存储起来。而流程控制语句则像是 “指挥官”&#xff0c;能够按照特定的逻辑对数组进行遍历和操作。接下来&#xff0c;就让我们…...

STM32中自动生成Flash地址的方法

每页大小为 2KB(0x800 字节),地址间隔为 0x800 总地址空间覆盖范围:0x08000000 ~ 0x0803F800(共 256KB) 适用于 STM32 大容量 / 中容量产品(如 F103 系列) 代码如下 // 通用定义(需根据实际页大小调整) #define FLASH_BASE_ADDR 0x08000000 #define FLASH_PAGE_SIZ…...

Matlab | MATLAB 中的插值详解

MATLAB 中的插值详解 插值是数值分析中的核心技术,用于在已知数据点之间估计未知点的值。MATLAB 提供了完整的插值函数库,涵盖一维到高维数据,支持多种插值方法。以下从基础到高级全面解析: 一、插值核心概念 1. 数学本质 给定数据点 ( x i , y i ) (x_i, y_i) (<...

SkyWalking架构深度解析:分布式系统监控的利器

一、SkyWalking概述 SkyWalking是一款开源的APM(应用性能监控)系统&#xff0c;专门为微服务、云原生和容器化架构设计。它由Apache软件基金会孵化并毕业&#xff0c;已成为分布式系统监控领域的明星项目。 核心特性 ‌分布式追踪‌&#xff1a;跨服务调用链路的完整追踪‌服务…...

vue2中的render函数

<script> export default {components: {},name: "renderElems",render (h, context) {return this.$attrs.vnode;},updated() {} } </script> <style scoped> </style>分析一下上面.vue组件&#xff1a; 组件结构&#xff1a; 这是一个非…...

逆向工程开篇(连载中)

项目特点 这个专栏专门设计用于汇编逆向工程研究&#xff0c;包含&#xff1a; ✅ 18个测试模块&#xff0c;覆盖所有主要C语言特性✅ 1200行工具类代码&#xff0c;400行主程序代码✅ 完整的Visual Studio 2017项目支持✅ Debug和Release两种构建配置✅ 静态库和可执行文件分…...

this.$set() 的用法详解(Vue响应式系统相关)

1. 什么是 this.$set()&#xff1f; this.$set(target, key, value) 是 Vue 2 中提供的一个方法&#xff0c;用于向响应式对象中动态添加属性&#xff0c;确保新加的属性同样是响应式的。 2. 为什么需要它&#xff1f; Vue 2 的响应式系统基于 Object.defineProperty&#…...

PARADISE:用于新生儿缺氧缺血性脑病(HIE)疾病识别与分割的个性化和区域适应性方法|文献速递-深度学习医疗AI最新文献

Title 题目 PARADISE: Personalized and regional adaptation for HIE disease identification and segmentation PARADISE&#xff1a;用于新生儿缺氧缺血性脑病&#xff08;HIE&#xff09;疾病识别与分割的个性化和区域适应性方法 1 文献速递介绍 缺氧缺血性脑病&…...

RabbitMQ 监控与调优实战指南(二)

五、调优策略与实战&#xff1a;对症下药提升性能 5.1 配置参数调优 在 RabbitMQ 的性能优化中&#xff0c;合理调整配置参数是关键的一环&#xff0c;这些参数涉及内存、磁盘、网络等多个资源层面&#xff0c;对 RabbitMQ 的整体性能有着深远的影响。 内存相关配置&#xf…...

WordPress子主题RiPro-V5van无授权全开源版(源码下载)

WordPress子主题RiPro-V5van无授权全开源版&#xff0c;直接上使用方法:WordPress后台上传就行 这个主题是1.0版本开源的&#xff0c;有能力的可以二次开发一下加一些自己喜欢的功能。 源码下载&#xff1a;https://download.csdn.net/download/m0_66047725/90952148 更多资…...