美文网首页
UITableView的理解

UITableView的理解

作者: QSY___Sunny | 来源:发表于2017-09-14 14:06 被阅读0次

    一、UITableView

    UITableView基本介绍

    UITableView在iOS开发中是应用最为广泛的一种控件。在了解UITableView之前,首先看一下iOS开发中UI控件的组织结构:

    UI控件组织结构

    从上图中可以看出,UITableView它的继承关系是:

    tableView继承关系

    因此UITableView可以响应事件、支持垂直滚动,⽽且性能极佳 。

    UITableView的结构

    UITableView的结构如下图所示:

    tableView结构图

    可以看出:
    一个tableView = 一个tableView HeaderView + 若干个section + 一个tableView FooterView;
    一个section = 一个section HeaderView + 若干个cell + 一个section FooterView ;

    UITableView的初始化方法为:

    // 设置表的大小、位置以及样式
    //(style:包括plain和group)
    - (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style;
    
    //或者用UIView的初始化方法,设置表的大小和位置
    - (instancetype)initWithFrame:(CGRect)frame;
    

    UITableView的风格

    UITableViewStyle是一个枚举,有两种样式:
    UITableViewStylePlainUITableViewStyleGrouped

    typedef NS_ENUM(NSInteger, UITableViewStyle) {
        UITableViewStylePlain,                  // 标准的表视图样式
        UITableViewStyleGrouped                 // 分组的表视图样式
    };
    

    两种样式如下图所示:

    tableView风格

    UITableView的属性

    常用的属性有:

    
    // 获取表视图的样式(plain和group)
    @property (nonatomic, readonly) UITableViewStyle style;
    
    // 可设置UITableViewDataSource的代理
    @property (nonatomic, weak, nullable) id <UITableViewDataSource> dataSource;
    
    // 可设置UITableViewDelegate的代理
    @property (nonatomic, weak, nullable) id <UITableViewDelegate> delegate;
    
    // tableView的行高、组头试图、组尾视图的高度,未设置时,返回默认值:-1.0
    // 当与代理方法同时实现时,按照代理方法中的高度进行设置
    @property (nonatomic) CGFloat rowHeight;             
    @property (nonatomic) CGFloat sectionHeaderHeight;
    @property (nonatomic) CGFloat sectionFooterHeight;
    
    // 性能优化(如果实现),估计tableView的行高、组头试图、组尾视图的高度,未设置时,返回默认值:0.0
    //在显示的时候回去调用heightForRowAtIndexPath,真正开始计算
    @property (nonatomic) CGFloat estimatedRowHeight;
    @property (nonatomic) CGFloat estimatedSectionHeaderHeight;
    @property (nonatomic) CGFloat estimatedSectionFooterHeight;
    
    // section的个数
    @property (nonatomic, readonly) NSInteger numberOfSections;
    
    // 返回可见的cells
    @property (nonatomic, readonly) NSArray<__kindof UITableViewCell *> *visibleCells;
    // 返回可见的位置
    @property (nonatomic, readonly, nullable) NSArray<NSIndexPath *> *indexPathsForVisibleRows;
    
    // 设置背景视图,只能写入,可根据tableView 的大小进行自动调整
    @property (nonatomic, strong, nullable) UIView *backgroundView
     
    /*
    * 编辑相关(Editing)
    */
    // 是否允许编辑,默认是NO
    @property (nonatomic, getter=isEditing) BOOL editing;
    - (void)setEditing:(BOOL)editing animated:(BOOL)animated;
    
    // 在非编辑下,行是否可以选中,默认为YES
    @property (nonatomic) BOOL allowsSelection;
    // 在编辑模式下,行是否可以选中,默认为NO
    @property (nonatomic) BOOL allowsSelectionDuringEditing;
    
    // 在非编辑模式下,是否允许同时选择多行,默认为NO
    @property (nonatomic) BOOL allowsMultipleSelection;
    // 在编辑模式下,是否允许同时选择多行,默认为NO
    @property (nonatomic) BOOL allowsMultipleSelectionDuringEditing;
    
    /*
    * 选择相关(Selection)
    */
    // 返回选定cell所对应的indexPath,单行,未选中时返回nil
    @property (nonatomic, readonly, nullable) NSIndexPath *indexPathForSelectedRow;
    // 返回选定cells所对应的indexPath集合,多行,未选中时返回nil
    @property (nonatomic, readonly, nullable) NSArray<NSIndexPath *> *indexPathsForSelectedRows; 
    
    /*
    * 显示相关(Appearance)
    */
    // 指定当tableView中多少行的时候开始显示IndexList,
    // 默认的设置是NSIntegerMax,即默认是不显示indexList的
    @property (nonatomic) NSInteger sectionIndexMinimumDisplayRowCount;
    
    // 索引号颜色
    @property (nonatomic, strong, nullable) UIColor *sectionIndexColor;   
      
    // 索引号背景颜色(未触摸/点击时显示的背景颜色)            
    @property (nonatomic, strong, nullable) UIColor *sectionIndexBackgroundColor;
    
    // 跟踪索引号背景颜色(触摸/点击时显示的背景颜色)
    @property (nonatomic, strong, nullable) UIColor *sectionIndexTrackingBackgroundColor;
    
    // cell之间分隔线的样式(默认是UITableViewCellSeparatorStyleSingleLine)
    @property (nonatomic) UITableViewCellSeparatorStyle separatorStyle;
    
    // cell的分割线的偏移。(UIEdgeInsets中的right、left起作用???)
    @property (nonatomic) UIEdgeInsets separatorInset; 
    
    // cell之间的分割线颜色(默认是灰色)
    @property (nonatomic, strong, nullable) UIColor *separatorColor;
    
    // 设置毛玻璃效果
    @property (nonatomic, copy, nullable) UIVisualEffect *separatorEffect;
    
    // if cell margins are derived from the width of the readableContentGuide.
    @property (nonatomic) BOOL cellLayoutMarginsFollowReadableWidth; 
    
    // 设置headerView
    @property (nonatomic, strong, nullable) UIView *tableHeaderView;                           
    // 设置footerView
    @property (nonatomic, strong, nullable) UIView *tableFooterView;                           
    
    // 记住上次的选择
    @property (nonatomic) BOOL remembersLastFocusedIndexPath;
    

    UITableView的方法

    
    // 表格进入编辑状态,是否有动画
    - (void)setEditing:(BOOL)editing animated:(BOOL)animated;
    
    /*
    * 数据相关(Data)
    */
    // 刷新整个表视图
    - (void)reloadData;
    // 刷新索引栏
    - (void)reloadSectionIndexTitles
    
    /*
    * 信息相关(Info)
    */
    // 获取某个组有多少行
    - (NSInteger)numberOfRowsInSection:(NSInteger)section;
    
    //根据section或indexPath获得section、headerView、footerView、row对应的CGRect
    // 获取某个组的位置和大小(包括头尾试图和所有行)
    - (CGRect)rectForSection:(NSInteger)section
    // 取某个组的头视图的位置和大小
    - (CGRect)rectForHeaderInSection:(NSInteger)section;
    // 取某个组的尾视图的位置和大小
    - (CGRect)rectForFooterInSection:(NSInteger)section;
    // 获取某一行的位置和大小
    - (CGRect)rectForRowAtIndexPath:(NSIndexPath *)indexPath;
    
    // 根据point、cell或rect获得indexPath
    // 根据某一点,返回indexPath(如果点不在tableView的任何一行上,则返回nil)
    - (nullable NSIndexPath *)indexPathForRowAtPoint:(CGPoint)point;  
    // 获取单元格的IndexPath信息(如果cell不可见,则返回nil)
    - (nullable NSIndexPath *)indexPathForCell:(UITableViewCell *)cell;
    // 返回某个区域内 多个单元格信息(如果rect无效,则返回nil)
    - (nullable NSArray<NSIndexPath *> *)indexPathsForRowsInRect:(CGRect)rect;
    // 通过单元格的indexPath得到单元格
    - (nullable __kindof UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath;
    
    // 获得头视图(可进行头视图设置)
    - (nullable UITableViewHeaderFooterView *)headerViewForSection:(NSInteger)section;
    // 获得尾视图(可进行尾视图设置)
    - (nullable UITableViewHeaderFooterView *)footerViewForSection:(NSInteger)section;
    
    /*
    * 插入、删除、更新、移动
    */
    // 二者配合使用
    //添加或删除前必须调用,只添加或删除才会更新行数
    - (void)beginUpdates;
    // 添加或删除后必须调用,只添加或删除方法时才会更新
    - (void)endUpdates;
    
    //对section进行插入、删除、更新、移动操作
    // 插入一个或多个section,并使用动画
    - (void)insertSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
    // 删除一个或多个section,并使用动画
    - (void)deleteSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
    // 更新一个或多个section,并使用动画
    - (void)reloadSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
    
    // 移动某一个section到目标section位置
    - (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection;
    
    //对row进行插入、删除、更新、移动操作
    // 插入一个或多个row,并使用动画
    - (void)insertRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
    // 删除一个或多个row,并使用动画
    - (void)deleteRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
    // 更新一个或多个row,并使用动画
    - (void)reloadRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
    // 移动某一个row到目标row位置
    - (void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath NS_AVAILABLE_IOS(5_0);
    
    /*
    * 选择相关
    */
    // 设置选中某个区域内的单元格
    - (void)selectRowAtIndexPath:(nullable NSIndexPath *)indexPath animated:(BOOL)animated scrollPosition:(UITableViewScrollPosition)scrollPosition;
    
    // 取消选中的单元格
    - (void)deselectRowAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated;
    
    /*
    * 重用机制
    */
    // 获取重用队列里的cell,代理调用
    - (nullable __kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier;
    - (__kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath;
    - (nullable __kindof UITableViewHeaderFooterView *)dequeueReusableHeaderFooterViewWithIdentifier:(NSString *)identifier
    
    /*
    * 注册
    */
    // 注册cell
    // 注册xib文件自定义的cell
    - (void)registerNib:(nullable UINib *)nib forCellReuseIdentifier:(NSString *)identifier;
    // 注册纯代码自定义的cell
    - (void)registerClass:(nullable Class)cellClass forCellReuseIdentifier:(NSString *)identifier;
    
    // 注册header,footer
    // 注册xib文件自定义的header,footer
    - (void)registerNib:(nullable UINib *)nib forHeaderFooterViewReuseIdentifier:(NSString *)identifier;
    // 注册xib文件自定义的header,footer
    - (void)registerClass:(nullable Class)aClass forHeaderFooterViewReuseIdentifier:(NSString *)identifier;
    

    2、UITableView的代理

    我们发现单元格高度、分组标题高度以及尾部说明的高度都需要调整,此时就需要使用代理方法。UITableView代理方法有很多,例如监听单元格显示周期、监听单元格选择编辑操作、设置是否高亮显示单元格、设置行高等:

    // 将要展示的cell会回调(可以在其中对cell进行修改设置)
    - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;
    // 将要展示的headView会回调
    - (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section;
    // 将要展示的headView会回调
    - (void)tableView:(UITableView *)tableView willDisplayFooterView:(UIView *)view forSection:(NSInteger)section;
    
    // 完成视图展示时回调,此时已经在界面上了
    // 完成展示的cell时,会回调
    - (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath*)indexPath;
    // 完成展示的headerView时,会回调
    - (void)tableView:(UITableView *)tableView didEndDisplayingHeaderView:(UIView *)view forSection:(NSInteger)section;
    // 完成展示的footerView时,会回调
    - (void)tableView:(UITableView *)tableView didEndDisplayingFooterView:(UIView *)view forSection:(NSInteger)section;
    
    /*
    * 高度设置相关
    */
    // 设置cell高度(这里高度通过协议返回,是为了table能准确的定位出要显示的Cell-index,从而满足UITableView的重用机制))
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
    // 设置headerView高度
    - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;
    // 设置footerView高度
    - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section;
    
    //性能优化(如果实现),加载的时候使用的是本方法,由于是一个固定的值,不需要计算,所以加载速度回很快,在显示的时候回去调用heightForRowAtIndexPath,真正开始计算。
    // row的估计高度
    - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath;
    // header的估计高度
    - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForHeaderInSection:(NSInteger)section;
    // footer的估计高度
    - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForFooterInSection:(NSInteger)section;
    
    /*
    * 自定义section的头尾视图相关
    */
    //可设置每个section-header和 footer 的自定义视图
    - (nullable UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section; 
    - (nullable UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section;
    
    /*
    * row的 Accessoriy 相关
    */
    // 可设置cell上Accessory的类型accessaryType(共5种)
    - (UITableViewCellAccessoryType)tableView:(UITableView *)tableView accessoryTypeForRowWithIndexPath:(NSIndexPath *)indexPath;
    // 设置cell上右指向Accessory的响应方法(当cell的accessaryType为UITableViewCellAccessoryDetailDisclosureButton时,
    // 点击accessaryView将会调用delegate的tableView:accessoryButtonTappedForRowWithIndexPath方法。否则只是didSelectRowAtIndexPath;)
    - (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath;
    
    /*
    * 选择(selection)相关
    */
    // 是否高亮
    // cell高亮回调,一般在选中的时候高亮
    - (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath;
    // cell一直高亮
    - (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath;
    // cell选中时不高亮
    - (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath;
    
    /* 先点击row0,再点击row1,俩着执行顺序(在下一行将要选中后才取消上一行的选中 ):
        willSelectRowAtIndexPath 当前row为:0 
        didSelectRowAtIndexPath 当前row为:0 
        willSelectRowAtIndexPath 当前row为:1 
        willDeselectRowAtIndexPath 当前row为:0 
        didDeselectRowAtIndexPath 当前row为:0 
        didSelectRowAtIndexPath 当前row为:1 
    */
    
    // 用户选择之前调用,将要选中
    - (nullable NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath;
    // 将要取消选中(此时已选中下一个row)
    - (nullable NSIndexPath *)tableView:(UITableView *)tableView willDeselectRowAtIndexPath:(NSIndexPath *)indexPath;
    // 用户选中时调用,已经选中当前行
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
    // 用户选择之后调用,取消选中(已经选中当前row)
    - (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath;
    
    /*
    * 编辑(editing)相关
    */
    // 返回编辑的类型1.没有2.删除3.插入
    - (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath;
    // 删除提示文本(删除确认按钮上的标题文字)
    - (nullable NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath;
    
    // 左滑小菜单 可以自定义想要的编辑操作 (要求ios8以上)
    - (nullable NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath
    
    // 编辑模式下,cell是否需要缩进,默认是YES(缩进),否则使用NO(只对grouped的TableView有效。)
    - (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath;
    // 用于设置缩进的级别
    - (NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath; 
    
    // 编辑状态发生改变时调用
    // 指定cell开始编辑时调用
    - (void)tableView:(UITableView *)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath;
    // 指定cell编辑完成时调用
    - (void)tableView:(UITableView *)tableView didEndEditingRowAtIndexPath:(nullable NSIndexPath *)indexPath
    
    /*
    * 复制(copy)相关
    */
    // 复制的时候三个方法都必须实现
    // 是否将要显示指定cell的菜单
    - (BOOL)tableView:(UITableView *)tableView shouldShowMenuForRowAtIndexPath:(NSIndexPath *)indexPath;
    // 是否能使用 sender 对指定cell进行执行操作
    - (BOOL)tableView:(UITableView *)tableView canPerformAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(nullable id)sender;
    //通过 sender 对指定cell执行操作
    - (void)tableView:(UITableView *)tableView performAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(nullable id)sender;
    
    /*
    * 移动(move)再排序相关
    */
    // 移动row时执行(将一个指定cell从source处移动到proposed(提议的)目标处  )
    - (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath;
    

    3、UITableView的数据源

    由于iOS是遵循MVC模式设计的,很多操作都是通过代理和外界沟通的,但对于数据源控件除了代理还有一个数据源属性,通过它和外界进行数据交互。

    数据源:(一般为控制器)根据索引路径(indexPath:可以定位到唯一的一个单元格)为某一个单元格提供数据。

    索引路径:(NSIndexpath)拥有两个属性section(段)、row(行),通过这两个属性即可定位UITableView中的唯一一个单元格cell

    对于UITableView设置完dataSource(tableView.dataSource=self)后,需要实现UITableViewDataSource协议:

    下面两个代理方法必须实现:

    @required //必须实现
    
    //每个section下行数(必须实现)
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
    //通过indexpath返回cell的具体样式和内容(必须实现)
    //可以在这里对cell进行设置(*这里使用了可以重复利用 UITableViewCell 的机制*)
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
    
    @optional //其他的代理方法可选实现:
    
    //返回分组section数,默认是1
    -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
    
    /*
    * 头尾标题内容(_字体样式固定,可以通过UILable改变_)
    */
    //返回每个section头标题内容
    -(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;
    //返回每个section尾部标题说明
    -(NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section;
    
    /*
    * 索引相关
    */
    //返回每个section标题索引(可以在这里设置索引)
    -(NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView;
    //点击索引触发(告诉tableView哪个section将会响应点击的索引 
    - (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index;
    
    /*
    * 编辑相关
    */
    //是否可编辑
    - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath;
    // 是否可拖拽(使用代理方法`tableView:moveRowAtIndexPath:toIndexPath:`之前设置)
    - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath;
    //插入/删除指定数据(根据编辑风格`editingStyle`确定是插入还是删除)
    - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath;
    
    //重新排序/移动数据操作
    - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath;
    

    cell的编辑风格UITableViewCellEditingStyle是个结构体,共有三个元素:没有风格、删除、插入:

    
    typedef NS_ENUM(NSInteger, UITableViewCellEditingStyle) {
        UITableViewCellEditingStyleNone,
        UITableViewCellEditingStyleDelete,
        UITableViewCellEditingStyleInsert
    };
    
    

    二、UITableViewCell基本介绍

    UITableViewCell的结构

    从上图中可以看到,在UITableView中数据只有行的概念,并没有列的概念,其中每行数据都是一个UITableViewCell。下图是UITableViewCell内置好的控件,可以看见contentView控件作为父控件,里面包括两个UILabel控件(textLabel,detailTextLabel),一个UIImage控件(imageView),一个AccessoryView,分别用于容器、显示内容、图片和详情(当然,这些子控件并不一定要全部使用):

    tableViewCell结构图

    UITableViewCell的示意图为:

    tableViewCell示意图

    UITableViewCell的风格

    UITableViewCell有四种风格,根据不同的分格,各个控件会进行不同的分布。四种风格分别为:

    
    typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
    UITableViewCellStyleDefault,    //左侧显示textLabel,不显示detailTextLabel,imageView可选(显示在最左边)
    UITableViewCellStyleValue1,     //左侧显示textLabel,右侧显示detailTextLabel,imageView可选(显示在最左边)
    UITableViewCellStyleValue2,     //左侧依次显示textLabel和detailTextLabel,不显示imageView
    UITableViewCellStyleSubtitle    //左上方显示textLabel,左下方显示detailTextLabel,imageView可选(显示在最左边)
    };
    
    

    UITableViewCellAccessoryType

    UITableViewCell中还可显示accessoryView(辅助指示视图),位于UITableViewCell的最右边,accessaryView的样式UITableViewCellAccessoryType有五种:

    
    typedef NS_ENUM(NSInteger, UITableViewCellAccessoryType) {
    UITableViewCellAccessoryNone,                   //没有视图  
    UITableViewCellAccessoryDisclosureIndicator,    //箭头
    UITableViewCellAccessoryDetailButton            //button
    UITableViewCellAccessoryDetailDisclosureButton, //button和箭头
    UITableViewCellAccessoryCheckmark,              //对勾
    };
    

    当然,我们也可以通过cell的accessoryView属性来自定义辅助指示视图(比如往右边放一个开关)。

    3、自定义UITableViewCell加载:代码&xib

    代码自定义

    方法一:(使用重用机制alloc一个cell,IDENTIFIER作为重用机制查找的标识)

    
    #define IDENTIFIER  @"identifier"
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        UITableViewCell* cell = nil;
    //使用重用机制,IDENTIFIER作为重用机制查找的标识,tableview查找可用cell时通过IDENTIFIER检索,如果有则cell不为nil
        cell = [tableView dequeueReusableCellWithIdentifier:IDENTIFIER];  
        if (cell == nil) {
            cell = [[TableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:IDENTIFIER];//代码创建的cell需要使用该初始化方法
        }
        return cell; 
    }
    

    ==注意:以上方式要注意cell创建时的Identifier与tableview dequeueReusableCell时是一样的。==

    方法二:(首先在viewdidload中调用registerClass注册cell)

    
    #define IDENTIFIER  @"identifier"
    首先在viewdidload中注册cell
    - (void)viewDidLoad {
        [super viewDidLoad];
        [self.tableView registerClass:[TableViewCell class] forCellReuseIdentifier:IDENTIFIER];
    }
    
    // 然后在tableview的delegate中
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        UITableViewCell* cell = nil;
        cell = [tableView dequeueReusableCellWithIdentifier:IDENTIFIER];
      //这里会发现,cell一直都不是nil,不再需要创建
        if (cell == nil) {
               NSLog(@"cell create at row:%ld", (long)indexPath.row);
        }
        return cell; 
    }
    

    ==通过注册cell类的方式,tableView dequeueReusableCellWithIdentifier 总是有值,即让tableview自己加载,不再需要手动创建cell,UICollectionViewCell也是类似。==

    xib自定义

    方法一:(代理方法中调用 loadNibNamed方法)

    
    #define IDENTIFIER  @"identifier"
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        UITableViewCell* cell = nil;
        cell = [tableView dequeueReusableCellWithIdentifier:IDENTIFIER];
        if (cell == nil) {
            cell = [[NSBundle mainBundle] loadNibNamed:@"TableViewCell" owner:nil options:nil].firstObject;
            NSLog(@"cell create at row:%ld", (long)indexPath.row);//此处要使用loadnib方式!
        }
        NSNumber* number = self.array[indexPath.row];
        cell.textLabel.text = number.stringValue;
        return cell; 
    }
    

    ==注意:TableviewCell为xib的名字,xib中的identifier必须与代码中的IDENTIFIER定义相同。==

    方法二:(首先在viewdidload中调用registerNib注册cell)

    
    #define IDENTIFIER  @"identifier"
    // 首先在viewdidload中注册cell
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        [self.tableView registerNib:[UINib nibWithNibName:@"TableViewCell" bundle:nil] forCellReuseIdentifier:IDENTIFIER];
    }
    // 然后在tableview的delegate中
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        UITableViewCell* cell = nil;
        cell = [tableView dequeueReusableCellWithIdentifier:IDENTIFIER];
        if (cell == nil) {
            //这里会发现,cell一直都不是nil,不再需要创建
            NSLog(@"cell create at row:%ld", (long)indexPath.row);
        }
        return cell; 
    }
    

    ==通过注册cell类的方式,让tableview自己加载,不再需要手动创建cell。==

    相关文章

      网友评论

          本文标题:UITableView的理解

          本文链接:https://www.haomeiwen.com/subject/lqvrsxtx.html