zoukankan      html  css  js  c++  java
  • iOS学习之UITableView(收藏贴)

    iOS学习之UITableView

     

    UITableView

    UITableView继承自UIScrollView,可以用来展示一组或多组内容样式相似的数据。UITableView几乎是iOS开发中运用最多的UI控件了,是iOS开发中必须掌握的控件之一。

    什么是UITableView?

    在众多移动应用中,能看到各式各样的列表数据:

      

    在iOS中,要实现展示列表数据,最常用的做法就是使用UITableView。UITableView继承自UIScrollView,因此支持垂直滚动,而且性能极佳。

    UITableView的两种样式:

    • UITableViewStylePlain:

    • UITableViewStyleGrouped:

    UITableViewCell简介:

    • UITableView的每一行都是一个UITableViewCell,通过dataSource的tableView:cellForRowAtIndexPath:方法来初始化每一行。

    • UITableViewCell内部有个默认的子视图:contentView,contentView是UITableViewCell所显示内容的父视图,可显示一些辅助指示视图。

    • 辅助指示视图的作用是显示一个表示动作的图标,可以通过设置UITableViewCell的accessoryType来显示,默认是UITableViewCellAccessoryNone(不显示辅助指示视图),其他值如下:
      • UITableViewCellAccessoryDisclosureIndicator 
      • UITableViewCellAccessoryDetailButton 
      • UITableViewCellAccessoryDetailDisclosureButton 
      • UITableViewCellAccessoryCheckmark 
      • 还可以通过cell的accessoryView属性来自定义辅助指示视图(比如往右边放一个开关)

    UITableViewCell的contentView:

    • contentView下默认有3个子视图
      • 其中2个是UILabel(通过UITableViewCell的textLabel和detailTextLabel属性访问)
      • 第3个是UIImageView(通过UITableViewCell的imageView属性访问)
    • UITableViewCell还有一个UITableViewCellStyle属性,用于决定使用contentView的哪些子视图,以及这些子视图在contentView中的位置

    UITableView的常见属性:

    /* tableView的样式 */
    @property (nonatomic, readonly) UITableViewStyle style;
    // tableView有两种样式
    //     UITableViewStylePlain  普通的表格样式
    //    UITableViewStyleGrouped  分组模式
    
    /* tableView的数据源 */
    @property (nonatomic, weak, nullable) id <UITableViewDataSource> dataSource;
    /* tableView的代理 */
    @property (nonatomic, weak, nullable) id <UITableViewDelegate> delegate;
    
    #pragma mark - 高度相关
    /* tableView每一行的高度,默认为44 */
    @property (nonatomic) CGFloat rowHeight;
    /* tableView统一的每一组头部的高度 */
    @property (nonatomic) CGFloat sectionHeaderHeight;
    /* tableView统一的每一组头部的高度 */
    @property (nonatomic) CGFloat sectionFooterHeight;
    /* 估算的tableView的统一的每一行行高 */
    @property (nonatomic) CGFloat estimatedRowHeight;
    /* 估算的统一的每一组头部高度,设置估算高度可以优化性能 */
    @property (nonatomic) CGFloat estimatedSectionHeaderHeight;
    /* 估算的统一的每一组的尾部高度 */
    @property (nonatomic) CGFloat estimatedSectionFooterHeight;
    
    /* 总共有多少组 */
    @property (nonatomic, readonly) NSInteger numberOfSections;
    /* 选中行的indexPath */
    @property (nonatomic, readonly, nullable) NSIndexPath *indexPathForSelectedRow;
    
    #pragma mark - 索引条
    /* 索引条文字的颜色 */
    @property (nonatomic, strong, nullable) UIColor *sectionIndexColor;
    /* 索引条的背景色 */
    @property (nonatomic, strong, nullable) UIColor *sectionIndexBackgroundColor;
    
    #pragma mark - 分隔线
    /* 分隔线的样式 */
    @property (nonatomic) UITableViewCellSeparatorStyle separatorStyle;
    // 分隔线的样式有:
    // UITableViewCellSeparatorStyleNone,  没有分隔线
    // UITableViewCellSeparatorStyleSingleLine, 正常分隔线
    @property (nonatomic, strong, nullable) UIColor *separatorColor; // 分隔线的颜色
    
    #pragma mark - 头尾部控件
    /* tableView的头部控件,只能设置高度,宽度默认填充表格 */
    @property (nonatomic, strong, nullable) UIView *tableHeaderView;
    /* tableView的尾部控件,只能设置高度,宽度默认填充表格*/
    @property (nonatomic, strong, nullable) UIView *tableFooterView;
    
    #pragma mark - 编辑模式
    /* 是否是编辑模式,默认是NO */
    @property (nonatomic, getter=isEditing) BOOL editing;
    /* tableView处在编辑模式的时候是否允许选中行,默认是NO */
    @property (nonatomic) BOOL allowsSelectionDuringEditing;
    /* tableView处在编辑模式的时候是否允许选中多行数据,默认是NO */
    @property (nonatomic) BOOL allowsMultipleSelectionDuringEditing;

    UITableViewCell的常见属性:

    #pragma mark - Cell内部子控件
    /*  默认为nil,imageView是懒加载,用到时才加载 */
    @property (nonatomic, readonly, strong, nullable) UIImageView *imageView;
    /* 默认为nil,是懒加载,用到时才加载 */
    @property (nonatomic, readonly, strong, nullable) UILabel *textLabel;
    /* 只有当Cell的样式为UITableViewCellStyleSubtitle时才会显示出来,默认为nil,是懒加载,用到时才加载 */
    @property (nonatomic, readonly, strong, nullable) UILabel *detailTextLabel;
    
    /* 当你想要自定义一个cell的时候,子控件最好添加到cell的contentView上,方便编辑表格 */
    @property (nonatomic, readonly, strong) UIView *contentView;
    
    /* cell的复用标识 */
    @property (nonatomic, readonly, copy, nullable) NSString *reuseIdentifier;
    
    /* cell的选中样式 */
    @property (nonatomic) UITableViewCellSelectionStyle   selectionStyle;
    /* cell是否是选中状态 */
    @property (nonatomic, getter=isSelected) BOOL         selected;
    
    /* cell的编辑样式,默认是UITableViewCellEditingStyleNone */
    @property (nonatomic, readonly) UITableViewCellEditingStyle editingStyle;
    // cell的编辑样式有:
    // UITableViewCellEditingStyleNone,
    // UITableViewCellEditingStyleDelete, 删除模式
    // UITableViewCellEditingStyleInsert   插入模式
    
    /* 指示器的样式,默认是UITableViewCellAccessoryNone */
    @property (nonatomic) UITableViewCellAccessoryType    accessoryType;
    // 指示器的样式有:
    // UITableViewCellAccessoryNone   不显示指示器
    // UITableViewCellAccessoryDisclosureIndicator cell右侧显示一个箭头
    // UITableViewCellAccessoryDetailDisclosureButton cell右侧显示一个箭头和一个详情图标
    // UITableViewCellAccessoryCheckmark cell右侧显示一个对勾
    // UITableViewCellAccessoryDetailButton cell右侧显示一个详情图标
    
    /* cell右侧指示器view,设置了以后,cell的accessoryType就会失效  */
    @property (nonatomic, strong, nullable) UIView       *accessoryView;

    UITableView的常用方法:

    /* 全局刷新 */
    - (void)reloadData;
    /* 刷新索引条 */
    - (void)reloadSectionIndexTitles;
    
    /* 返回第section组有多少行 */
    - (NSInteger)numberOfRowsInSection:(NSInteger)section;
    /* 返回indexPath对应的那一行的cell */
    - (nullable __kindof UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath;
    
    /* 返回第section组的头部view */
    - (nullable UITableViewHeaderFooterView *)headerViewForSection:(NSInteger)section;
    /* 返回第section组的尾部view */
    - (nullable UITableViewHeaderFooterView *)footerViewForSection:(NSInteger)section;
    
    /**
     *  插入数据,刷新数据
     *  @param indexPaths 插入在哪个位置
     *  @param animation  动画效果,枚举UITableViewRowAnimation
     */
    - (void)insertRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
    
    /**
     *  删除数据
     *  @param indexPaths 删除数据的位置
     *  @param animation  动画效果,枚举UITableViewRowAnimation
     */
    - (void)deleteRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
    // 枚举UITableViewRowAnimation包括:
    // UITableViewRowAnimationFade,  淡入淡出
    // UITableViewRowAnimationRight,  向右滑动
    // UITableViewRowAnimationLeft,  向左滑动
    // UITableViewRowAnimationTop,  向上滑动
    // UITableViewRowAnimationBottom,  向下滑动
    // UITableViewRowAnimationNone,  无动画效果,iOS 3.0以后可用
    // UITableViewRowAnimationMiddle,  保持cell的中间,iOS 3.2以后可用
    // UITableViewRowAnimationAutomatic  自动选择一个合适的动画效果
    
    /**
     *  刷新某一行的数据
     *  @param indexPaths 刷新数据的位置
     *  @param animation  动画效果,枚举UITableViewRowAnimation
     */
    - (void)reloadRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
    
    /** 动画开启/关闭编辑模式 */
    - (void)setEditing:(BOOL)editing animated:(BOOL)animated;
    
    /** 返回一个带有复用标识的cell */
    - (nullable __kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier;
    
    /**
     *  使用xib时注册自定义的cell
     *  @param nib        要注册的nib
     *  @param identifier 复用标识
     */
    - (void)registerNib:(nullable UINib *)nib forCellReuseIdentifier:(NSString *)identifier;
    
    /**
     *   代码自定义cell时注册自定义的cell
     *  @param cellClass  注册的自定义cell的类型
     *  @param identifier 复用标识
     */
    - (void)registerClass:(nullable Class)cellClass forCellReuseIdentifier:(NSString *)identifier;
    
    /** 初始化一个带有复用标识的cell */
    - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(nullable NSString *)reuseIdentifier
    

    UITableViewDataSource中的常用方法:

    // 必须实现的方法:
    /* 设置第section组有多少行数据 */
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
    /* 设置每一行cell的内容,每当有一个cell进入视野屏幕的时候就会调用这个方法,所以在这个方法内部进行优化(cell的复用) */
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
    
    // 可实现可不实现的方法:
    /* 总共有多少组,如果不实现,默认是一组 */
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
    
    /* 第section组的头部标题 */
    - (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;
    /* 第section组的尾部标题 */
    - (nullable NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section;
    
    /** 设置索引条 */
    - (nullable NSArray<NSString *> *)sectionIndexTitlesForTableView:(UITableView *)tableView;

    UITableViewDelegate中的常用方法:

    /** 设置每一行cell的高度 */
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
    /** 设置第section组的头部高度 */
    - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;
    /** 设置第section组的尾部高度 */
    - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section;
    
    /** 每一行的估算高度 */
    - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath;
    
    /** 设置第section组的headerView */
    - (nullable UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section;
    /** 设置第section组的footerView */
    - (nullable UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section;
    
    /** 选中了某一行cell的时候就会调用这个方法 */
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
    
    /**
     *  设置左滑删除按钮的文字
     *  @param tableView         被编辑的tableView
     *  @param indexPath         indexPath
     *  @return 返回删除按钮显示的文字
     */
    - (nullable NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath;
    
    /**
     *  创建一个左滑出现按钮的操作(UITableViewRowAction)数组
     *  @param tableView         添加操作的tableView
     *  @param indexPath         indexPath,可以指定每一行有不同的效果
     *  @return 返回一个操作(UITableViewRowAction)数组
     */
    - (nullable NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath;
    
    /**
     *  移动cell
     *  @param tableView            操作的tableView
     *  @param sourceIndexPath      移动的行
     *  @param destinationIndexPath 目标行
     */
    - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath;
    
    /** 根据editingStyle处理是删除还是添加操作,完成删除、插入操作刷新表格 */
    - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath;
    
    /**
     *  设置表格编辑模式,不实现默认都是删除
     *  @param tableView 操作的tableView
     *  @param indexPath cell的位置
     *  @return 返回表格编辑样式
     */
    - (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath;

    tableView如何展示数据:

    • UITableView需要一个数据源(dataSource)来显示数据
    • UITableView会向数据源查询一共有多少行数据以及每一行显示什么数据等
    • 没有设置数据源的UITableView只是个空壳
    • 凡是遵守UITableViewDataSource协议的OC对象,都可以是UITableView的数据源

    tableView展示数据的过程:

    设置数据源,遵守UITableViewDataSource协议,实现协议方法:

    @interface ViewController ()<UITableViewDataSource,UITableViewDelegate>
    
    @property (weak, nonatomic) IBOutlet UITableView *tableView;
    
    @end
    
    - (void)viewDidLoad{
        [super viewDidLoad];
    
        self.tableView.dataSource = self;
    }
    
    #pragma mark - UITableViewDataSource
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
        // 在这个方法中设置总共有多少组数据
        // 这个方法如果不实现,默认是一组
    }
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
        // 在这个方法中设置第section组有多行数据
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
        // 1.定义一个cell的复用标识
          static NSString *ID = @"cell";
    
        // 2.根据复用标识,从缓存池中取出带有同样的复用标识的cell
          UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    
        // 3.如果缓存池中没有带有这种复用标识的cell,就创建一个带有这种复用标识的cell
          if (cell == nil) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
        }
    
        // 4.设置cell的一些属性
    
        return cell;
    }
    
    - (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section{
        // 在这个方法中设置第section组的尾部标题
    }
    
    - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
        // 在这个方法中设置第section组的头部标题
    }
    
    #pragma mark - UITableViewDelegate
    
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
        // 当选中了某一行的时候就会调用这个方法,可以在这里进行一些操作
    }
    

    Cell的重用原理:

    iOS设备的内存有限,如果用UITableView显示成千上万条数据,就需要成千上万个UITableViewCell对象的话,那将会耗尽iOS设备的内存。要解决该问题,需要重用UITableViewCell对象。

    重用原理:当滚动列表时,部分UITableViewCell会移出窗口,UITableView会将窗口外的UITableViewCell放入一个缓存池中,等待重用。当UITableView要求dataSource返回UITableViewCell时,dataSource会先查看这个缓存池,如果池中有未使用的UITableViewCell,dataSource会用新的数据配置这个UITableViewCell,然后返回给UITableView,重新显示到窗口中,从而避免创建新对象。

    还有一个非常重要的问题:有时候需要自定义UITableViewCell(用一个子类继承UITableViewCell),而且每一行用的不一定是同一种UITableViewCell,所以一个UITableView可能拥有不同类型的UITableViewCell,缓存池中也会有很多不同类型的UITableViewCell,那么UITableView在重用UITableViewCell时可能会得到错误类型的UITableViewCell。

    解决方案:UITableViewCell有个NSString *reuseIdentifier属性,可以在初始化UITableViewCell的时候传入一个特定的字符串标识来设置reuseIdentifier(一般用UITableViewCell的类名)。当UITableView要求dataSource返回UITableViewCell时,先通过一个字符串标识到缓存池中查找对应类型的UITableViewCell对象,如果有,就重用,如果没有,就传入这个字符串标识来初始化一个UITableViewCell对象。

    通过代码自定义cell(cell的高度不一致):

    这里提供的思路并未使用自动布局,是纯手码计算frame。

    • 1.新建一个继承自UITableViewCell的类。
    • 2.重写initWithStyle:reuseIdentifier:方法
      • 添加所有需要显示的子控件(不需要设置子控件的数据和frame, 子控件要添加到contentView中)
      • 进行子控件一次性的属性设置(有些属性只需要设置一次, 比如字体、固定的图片)
    • 3.提供2个模型
      • 数据模型: 存放文字数据、图片数据
      • frame模型: 存放数据模型、所有子控件的frame、cell的高度
    • 4.cell拥有一个frame模型(不要直接拥有数据模型)
    • 5.重写frame模型属性的setter方法: 在这个方法中设置子控件的显示数据和frame
    • 6.frame模型数据的初始化已经采取懒加载的方式(每一个cell对应的frame模型数据只加载一次)
  • 相关阅读:
    spring cloud 和 阿里微服务spring cloud Alibaba
    为WPF中的ContentControl设置背景色
    java RSA 解密
    java OA系统 自定义表单 流程审批 电子印章 手写文字识别 电子签名 即时通讯
    Hystrix 配置参数全解析
    spring cloud 2020 gateway 报错503
    Spring Boot 配置 Quartz 定时任务
    Mybatis 整合 ehcache缓存
    Springboot 整合阿里数据库连接池 druid
    java OA系统 自定义表单 流程审批 电子印章 手写文字识别 电子签名 即时通讯
  • 原文地址:https://www.cnblogs.com/wangxiaorui/p/5133529.html
Copyright © 2011-2022 走看看