iOS之UITableView略解

一.UITableView的重要性

  1. 产品上讲:
    App靠内容黏住用户,没有内容的App,注定是没有生命力的。 而UITableView,便是用于海量数据的展示,我们平时使用的软件中到处都可以看到它的影子,类似于微信、QQ、新浪微博等软件基本上随处都是UITableView

  2. 技术上讲:
    UITableView具有重用和延迟加载等特性, 只要正确使用,海量的数据便可在这张表上,一览无余;
    我们可以借鉴苹果设计UITableView的思想来自定义控件(这点很重要)

二.UITableView的结构

  1. tableView的大致结构


    结构.png
  2. tableViewCell
    cell苹果提供了四种类型

cell苹果提供了四种类型

本例的示意图是用xib自定义的cell

accessory view

accessory view苹果也提供了几种类型


Snip20160511_13.png

Paste_Image.png

三.本人项目中常用的方法(比较乱,请谅解)

1.两种初始化的方式
UITableViewStylePlain,UITableViewStyleGrouped
看看官方文档的解释:


UITableViewStylePlain.png
UITableViewStyleGrouped.png
  • 区别一:(翻译一下子)
    UITableViewStylePlain形式的tableView section的headerView和footerView会浮动
    UITableViewStyleGrouped形式的tableView则不会
  • 区别二:这个文字不好描述,还是直接上图吧
UITableViewStylePlain.png
UITableViewStyleGrouped.png

UITableViewStyleGrouped形式的tableView,若要修改section之间的距离,需要实现以下四个代理方法:

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
    
}

- (UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {

}

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
   
}

- (UIView*)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
 
}

2.闭合cell的分割线(相信有很多开发者碰到这样的需求,默认的分割线左边是没有闭合的)
实现以下代理:

-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
   
    if ([cell respondsToSelector:@selector(setSeparatorInset:)]) {
        [cell setSeparatorInset:UIEdgeInsetsZero];
    }
    
    if ([cell respondsToSelector:@selector(setPreservesSuperviewLayoutMargins:)]) {
        [cell setPreservesSuperviewLayoutMargins:NO];
    }
    
    if ([cell respondsToSelector:@selector(setLayoutMargins:)]) {
        [cell setLayoutMargins:UIEdgeInsetsZero];
    }
}

3.取消cell的分割线

  • 第一种方式
    设置tableView的separatorStyle 为UITableViewCellSeparatorStyleNone
    苹果提供了如下枚举
typedef NS_ENUM(NSInteger, UITableViewCellSeparatorStyle) {
    UITableViewCellSeparatorStyleNone,
    UITableViewCellSeparatorStyleSingleLine,
    UITableViewCellSeparatorStyleSingleLineEtched   // This separator style is only supported for grouped style table views currently
} __TVOS_PROHIBITED;

第三个说是只在grouped style table views才可以用但是和UITableViewCellSeparatorStyleNone的效果是一样的,不知道是不是bug(应该是我太菜,没理解)

  • 第二种方式
    这种方式的好处在于只让某个cell的分割线取消时,比较好处理
[cell setSeparatorInset:UIEdgeInsetsMake(0, 0, 0, 1000000)];

4.关于自定义cell

  • 第一种方式:xib拖
  • 第二种方式:纯代码
// xib方式的注册
[_tableView registerNib:[UINib nibWithNibName:@"" bundle:nil] forCellReuseIdentifier:@""];
// 纯代码方式的注册
 [_tableView registerClass:[Cell class] forCellReuseIdentifier:@""];

注意:纯代码的cell布局尽量在这里处理

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        [self layoutCellUI];
    }
    return self; 
}

5.cell的selectionStyle
首先看下官方提供的几种:

typedef NS_ENUM(NSInteger, UITableViewCellSelectionStyle) {
    UITableViewCellSelectionStyleNone,
    UITableViewCellSelectionStyleBlue,
    UITableViewCellSelectionStyleGray,
    UITableViewCellSelectionStyleDefault NS_ENUM_AVAILABLE_IOS(7_0)
};

如果我们要自定义选中状态呢?

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
    if (selected) {
        self.selectedBackgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"xozaa_discover_activity"]];
        self.lblText.textColor = [UIColor whiteColor];
    } else {
        self.selectedBackgroundView = nil;
        self.lblText.textColor = [UIColor blackColor];
    }
}

效果如下:


效果图

这里需要注意的就是cell里其他控件的状态改变是否要变化

6.取消选中状态
[tableView deselectRowAtIndexPath:indexPath animated:YES];

如果有这样的需求:跳转到另一个页面再回到本页面,要告诉用户我刚才点了哪个cell,那么我们可以这样处理:

(void) viewWillAppear: (BOOL)inAnimated {
NSIndexPath *selectedIndexPath = [self.table indexpathForSelectedRow];
if(selectedIndexPath)  {
    [self.table deselectRowAtIndexpath:selectedIndexPath animated:NO];
  }
}

7.cell的赋值
tableView的数据处理应该大部分都用数组处理吧,假设以数组处理,如下

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    TestTableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"TestTableViewCell"];
    
    NSDictionary* dic = _arr[indexPath.row];
    [cell fillData:dic];

    return cell;
}

这里要说的是给cell填充数据时,我们尽量不要在ViewController里边写,展示的事情应该交给View层去处理,ViewController只是把Model的数据发送过去。

之前见过实现这个代理时写的超长的方法,所有的业务逻辑,展示逻辑都在这里,看这种代码的时候真的很痛苦

减轻ViewController的压力,维护起来也很方便

8.左滑cell处理
实现如下代理,注意这个代理仅支持iOS8以后的系统

- (nullable NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(8_0) __TVOS_PROHIBITED;

效果图:

效果图.png

直接上代码


#pragma mark -  UITableViewDelegate
/**
 *  左滑事件
 *
 *  @param tableView
 *  @param indexPath
 *
 *  @return 数组
 */
- (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {
    // 删除按钮
    UITableViewRowAction *deleteRowAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"删除" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath){
        NSLog(@"删除");
        // 注意数据源对应删除,否则会报Assertion failure in -[UITableView _endCellAnimationsWithContext:] 这样的错误
        // 如果一个分组中,有多条数据时,你删除其中一条,正确;当一个分组中,你要删除唯一的一条时,仍然会报出如上的错误!,测试需要删除这个section
        if (indexPath.section == 1) {
            [arr2 removeObjectAtIndex:indexPath.row];
            [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
        }
    }];
    
    // 置顶按钮
    UITableViewRowAction *toTopRowAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"置顶" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath){
        NSLog(@"置顶");
        // 注意数据源对应处理
        [tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];
    }];
    // 设置按钮的背景色
    toTopRowAction.backgroundColor = [UIColor orangeColor];
    
    // 其他按钮
    UITableViewRowAction *otherRowAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"其他" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath){
        NSLog(@"其他");
    }];
    // 设置按钮的背景色
    otherRowAction.backgroundColor = [UIColor cyanColor];
    
    //返回按钮数组
    return @[deleteRowAction, toTopRowAction, otherRowAction];
}

9.各种reload
假设我们的tableView初始化已经完毕

@property (nonatomic,strong) UITableView *tableView;

// 刷新整个表
[self.tableView reloadData];

// 某个section的刷新
NSIndexSet *indexSet=[[NSIndexSet alloc]initWithIndex:2];
[self.tableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationAutomatic];

// 某个cell的刷新
NSIndexPath *indexPath=[NSIndexPath indexPathForRow:3 inSection:0];
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];

10 UITableView初级优化
如果我们的cell高度是固定的,那么我强烈建议定义cell高度的地方放到初始化的时候
而不要去走代理方法:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
     return 100.0;
}

很多人都把优化的重点放到了 cell for row at indexpath 那个方法里了,在这里尽可能的少计算,但是却忽略了另一个很轻松就能提升加载时间的方法 :

eg:_tableView.rowHeight = 100.0;

Table View 在每次 reload data 时都会要所有 cell 的高度!这就是说你有一百行 cell,就x向代理要100次每个cell 的高度,而不是当前屏幕显示的cell 的数量的高度!减少 计算高度时的时间,对于提升加载 Table View 的速度有非常明显的提高!


暂时先写这么多吧,其实还有很多小细节没提及到(tableView的刷新,section的刷新,cell的刷新,cell的添加、删除,表格右边建立一个浮动的索引,控制该表格滚动到指定indexPath等等)这篇是比较基础的东东,但还是希望会给大家带来帮助 O(∩_∩)O

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,287评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,346评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,277评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,132评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,147评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,106评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,019评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,862评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,301评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,521评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,682评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,405评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,996评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,651评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,803评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,674评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,563评论 2 352

推荐阅读更多精彩内容