Nadeal

您现在的位置是:首页>所属分类

所属分类

iOS中UITableView的常用方法和属性汇总

Nadeal2022年4月17日 10:12个人博客531
UITableView是开发中非常常见的一种控件,使用频率非常高。对它的方法进行一个记录,也是一件好事。

一、简介
1. 继承关系

UITableView继承自UIScrollView,因此支持垂直滚动,而且性能极佳。UITableView的代理协议也继承了UIScrollView的代理协议,可以通过实现UIScrollView的代理方法,监听UITableView的变化。在UITableView中没有列的概念,只有行的概念,数据都是按行显示的。
2.使用场景

在iOS中,通常使用UITableView实现表格数据展示
3. 基本概念

Plain:单组样式,整个UITableView只有一组数据
Grouped:多组样式,整个UITableView有多组数据
dataSource:数据源,用于设置UITableView展示的数据
delegate:代理,用于监听UITableView的操作和对UITableView的一些属性进行设置
row:行,在每一行上展示数据,每一行对应一个cell
section:组,UITableView中可以把相似的内容分维一组
Header:头部,一组的头部
Footer:尾部,一组的尾部
estimatedHeight:估计高度,有估计行高、估计头部高度、有估计尾部高度;给系统一个估算高度,系统会先创建一个cell,然后再调用设置行高的方法
Selection:选中
reload:刷新,创新装载数据
缓冲池获取cell:在缓存池中获取带有对应标记的cell

4. Cell的简介

(1).UITableView的每一行都是一个UITableViewCell对象,通过dataSource的tableView:cellForRowAtIndexPath:方法来初始化每一行
(2).常见属性

imageView:用于显示图片
textLabel:用于显示大标题
detailTextLabel:用于显示小标题
contentView:contentView是UITableViewCell所显示内容的父视图,可显示一些辅助指示视图,自定义cell的子控件都添加到contentView中
backgroundView:添加一个背景视图,可以用于设置cell普通状态下的背景颜色
selectedBackgroundView:选中一个cell之后的背景视图,可用于设置选中时候的背景颜色
multipleSelectionBackgroundView:选中多个时候的背景视图,可用于设置选中多个时候的背景颜色
reuseIdentifier:用于给cell设置一个标识,设置标识的cell用于性能优化
selectionStyle:选中时候的显示类型
selected:设置是否选中
highlighted:是否在选中的时候呈现高亮

(3).常见方法

// 初始化一个cell和设置cell的标识
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier NS_AVAILABLE_IOS(3_0);

二、常见属性

// UITableView类型,类型有单组和多组
@property (nonatomic, readonly) UITableViewStyle style;
// 数据源
@property (nonatomic, assign) id <UITableViewDataSource> dataSource;
// 代理
@property (nonatomic, assign) id <UITableViewDelegate> delegate;
// 行高
@property (nonatomic) CGFloat rowHeight;
// 组的头部高度
@property (nonatomic) CGFloat sectionHeaderHeight; 
// 组的尾部高度
@property (nonatomic) CGFloat sectionFooterHeight;   
// 行的估计高度
@property (nonatomic) CGFloat estimatedRowHeight NS_AVAILABLE_IOS(7_0); 
// 组的头部的估计高度
@property (nonatomic) CGFloat estimatedSectionHeaderHeight NS_AVAILABLE_IOS(7_0); 
// 组的尾部的估计高度
@property (nonatomic) CGFloat estimatedSectionFooterHeight 
// 设置背景视图
@property(nonatomic, readwrite, retain) UIView *backgroundView NS_AVAILABLE_IOS(3_2);
// 设置头部显示的视图
@property (nonatomic, retain) UIView *tableHeaderView;                           
// 设置尾部显示的视图
@property (nonatomic, retain) UIView *tableFooterView;
// 是否可以编辑
@property (nonatomic, getter=isEditing) BOOL editing;

三、常见方法

1. 关于TableView初始化

// 初始化一个tableView和设置tableView的样式
- (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style;

2. 关于TableView数据更新

// 所有数据全部更新
- (void)reloadData; 
// 更新索引
- (void)reloadSectionIndexTitles NS_AVAILABLE_IOS(3_0);

3.关于TableView的信息

// 获取UITableView有多少组
- (NSInteger)numberOfSections;
// 获取第section组有多少行
- (NSInteger)numberOfRowsInSection:(NSInteger)section;
// 获取第section的位置和尺寸大小
- (CGRect)rectForSection:(NSInteger)section;
// 获取第section的头部的位置和尺寸大小
- (CGRect)rectForHeaderInSection:(NSInteger)section;
// 获取第section的尾部的位置和尺寸大小
- (CGRect)rectForFooterInSection:(NSInteger)section;
// 获取第indexPath.section组第indexPath.row行的位置和尺寸大小
- (CGRect)rectForRowAtIndexPath:(NSIndexPath *)indexPath;
// 获取原点point所在的行的位置indexPath
- (NSIndexPath *)indexPathForRowAtPoint:(CGPoint)point;
// 获取指定的cell的位置indexPath
- (NSIndexPath *)indexPathForCell:(UITableViewCell *)cell;
// 获取rect范围内的所有行的位置indexPath所组成的数组
- (NSArray *)indexPathsForRowsInRect:(CGRect)rect; 
// 获取indexPath位置的cell
- (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath;
// 获取看得见的所有的cell所组成的数组
- (NSArray *)visibleCells;
// 获取看得见的所有的cell的位置indexPath所组成的数组
- (NSArray *)indexPathsForVisibleRows;
// 获取第section组头部的view
- (UITableViewHeaderFooterView *)headerViewForSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);
// 获取第section组尾部的view
- (UITableViewHeaderFooterView *)footerViewForSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);

4. 关于行或组的插入、删除、更新

// 配合beginUpdates方法使用,在一个代码块中,提示开始更新,代码块中写对行或组的插入、删除
- (void)beginUpdates;
// 配合beginUpdates方法使用,在一个代码块中,提示结束更新,代码块中写对行或组的插入、删除
- (void)endUpdates;  
// 插入组数据
- (void)insertSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
// 删除组数据
- (void)deleteSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
// 更新组数据
- (void)reloadSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation NS_AVAILABLE_IOS(3_0);
// 移动组
- (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection NS_AVAILABLE_IOS(5_0);
// 插入行
- (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
// 删除行
- (void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
// 更新行
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation NS_AVAILABLE_IOS(3_0);
// 移动行
- (void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath NS_AVAILABLE_IOS(5_0);

5.关于选中的方法

// 获取选中行的位置indexPath
- (NSIndexPath *)indexPathForSelectedRow; 
// 获取选中多行的位置indexPath所组成的数组
- (NSArray *)indexPathsForSelectedRows NS_AVAILABLE_IOS(5_0);

6. 关于cell的重利用方法

// 重利用标识为identifier的cell,如果注册过Cell,在没有可用的cell时,会返回nil
- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier;
// 重利用标识为identifier的cell,如果你没有注册过cell,在没有可用的cell时,程序直接崩溃
- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(6_0);
// 重利用标识为identifier的自定义的头部或尾部
- (id)dequeueReusableHeaderFooterViewWithIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(6_0);

7.关于cell的注册方法

// 注册xib创建的cell,设标识为identifier
- (void)registerNib:(UINib *)nib forCellReuseIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(5_0);
// 注册cellClass创建的cell,设标识为identifier
- (void)registerClass:(Class)cellClass forCellReuseIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(6_0);
// 注册xib创建的头部或尾部,设标识为identifier
- (void)registerNib:(UINib *)nib forHeaderFooterViewReuseIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(6_0);
// 注册aClass创建的头部或尾部,设标识为identifier
- (void)registerClass:(Class)aClass forHeaderFooterViewReuseIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(6_0);

四、数据源

要让tableView显示数据,要设置数据源,并实现必要的数据源方法

// 设置第section组的行数,必选
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
// 设置位置为indexPath的cell,必选
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
// 设置tableView的组数,不实现该方法就默认只有一组
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
// 设置第section组的头部
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection(NSInteger)section;
//  设置第section组的尾部
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section;
// 设置位置为indexPath的是否可以编辑,与tableview:commitEditingStyle:方法配合使用
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath;
// 当某一行可进行编辑时,实现该方法可以对那一行进行编辑
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath;
// 设置位置为indexPath的是否可以移动, 与tableview:moveRowAtIndexPath方法配合使用
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath;
// 移动时使用
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath;
// 给组添加索引
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView; 
// 设置每一组对应的索引,index表示组号,title表示索引标题
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index;

五、代理

tableView的代理可以实现scrollView的代理方法,因为协议继承了scrollView代理协议

1.关于监听显示的方法

// 即将显示位置为indexPath的cell时调用
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;
// 即将显示第section组的头部时调用
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);
// 即将显示第section组的尾部时调用
- (void)tableView:(UITableView *)tableView willDisplayFooterView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);
// 位置为indexPath的cell不再在屏幕上显示时调用
- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath*)indexPath NS_AVAILABLE_IOS(6_0);
// 第section组的头部不再在屏幕上显示时调用
- (void)tableView:(UITableView *)tableView didEndDisplayingHeaderView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);
// 第section组的尾部不再在屏幕上显示时调用
- (void)tableView:(UITableView *)tableView didEndDisplayingFooterView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);

2.关于设置高的方法

// 设置行高
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
// 设置头部的高
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;
// 设置尾部的高
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section;

3.关于设置估计高的方法

// 估计行高
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(7_0);
// 估计头部的高
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForHeaderInSection:(NSInteger)section NS_AVAILABLE_IOS(7_0);
// 估计尾部的高
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForFooterInSection:(NSInteger)section NS_AVAILABLE_IOS(7_0);

4.关于自定义头部或尾部标题的view的方法

// 设置自定义View的头部
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section; 
// 设置自定义view的尾部
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section;

六、性能优化
1.问题

iOS设备的内存有限,如果用UITableView显示成千上万条数据,就需要成千上万个UITableViewCell对象,那将会耗尽iOS设备的内存。要解决该问题,需要重用UITableViewCell对象
2.苹果已经进行一次优化

优化:看到的cell才创建,看不见的cell就销毁。
但其实苹果没有销毁cell,只是把它放到了缓存池中
3.程序员的再次优化

思想:当要显示新的cell时,如果缓存池中有类似的cell就直接拿过来重用
(1).重用原理
当滚动列表时,部分UITableViewCell会移出窗口,UITableView会将窗口外的UITableViewCell放入一个对象池中,等待重用。当UITableView要求dataSource返回UITableViewCell时,dataSource会先查看这个对象池,如果池中有未使用的UITableViewCell,dataSource会用新的数据配置这个UITableViewCell,然后返回给UITableView,重新显示到窗口中,从而避免创建新对象。有时候需要自定义UITableViewCell(用一个子类继承UITableViewCell),而且每一行用的不一定是同一种UITableViewCell,所以一个UITableView可能拥有不同类型的UITableViewCell,对象池中也会有很多不同类型的UITableViewCell,那么UITableView在重用UITableViewCell时可能会得到错误类型的UITableViewCell
(2).解决方案
UITableViewCell有个NSString *reuseIdentifier属性,可以在初始化UITableViewCell的时候传入一个特定的字符串标识来设置reuseIdentifier(一般用UITableViewCell的类名)。当UITableView要求dataSource返回UITableViewCell时,先通过一个字符串标识到对象池中查找对应类型的UITableViewCell对象,如果有,就重用,如果没有,就用传入的这个字符串标识来初始化一个新的UITableViewCell对象
七、注意

1.同时设置cell的选中背景View和默认背景View,设置默认背景View优先级更高
2.在对cell进行编辑操作时,模型和cell的行数必须一致,不然会报错
3.在storyboard中的tableView中添加cell,可以拖控件UITableViewCell,也可以在tableView的属性栏设置Prototype Cells的个数
4.不设置tableView的数据源,即使实现了数据源协议的方法也不能显示数据
5.不设置tableView的代理,即使实现了代理协议的方法也不能显示数据
6.关于估计高度:只要返回了估计高度,那么就会先调用tableView:cellForRowAtIndexPath:方法创建cell,再调用tableView:heightForRowAtIndexPath:方法获取cell的真实高度
7.当控件的约束刚设置时,如果要紧接着使用控件的Frame,要先调用layoutIfNeeded方法进行强制布局,系统才对控件的Frame进行设置,否则Frame为0
8.设计自定义cell时,应该先把所有可能出现的控件布置好,哪些暂时不需要显示的可以隐藏,在需要显示时再取消隐藏
9.应该充分利用模型,因为模型始终贯穿tableView,可以用于记录一些cell的不确定的属性,如不等高时,用模型记录每一个cell不同的高