iOS 中 UITableView 某个场景的使用

最近在想关于 UITableView 的一些事,对于界面搭建来说,它是再常用不过了,对于它可以说的事,实在是太多了,然而我这两天想的是应用场景的一些情形,其中有一些疑问。

多种样式,多种点击的列表
  • 1、多种点击的列表,假如还是传统方式,那么判断是否太多了一点
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    switch (indexPath.row) {
        case 0: {
            
        }
            break;
        default:
            break;
    }
}

  • 2、多种样式的列表,用一个 UITableViewCell 肯定是不行的
    此时肯定是多个 Cell ,甚至有种感觉此时不如直接用 UIButton 是否都会更方便一些,更好扩展一些呢?

  • 3、另外例如淘宝首页这种界面,此时又该怎么办呢?

复杂的 Home 界面

当然据说他们是采取了他们自己的 ListView, 此处不做讨论,只是假如我们自己要实现的情况下,又应该怎么办呢?

我想我的实现首先肯定是整体的 UICollectionView + HeaderView, 而此处复杂的是 HeaderView, 高度和滑动的实现,所以此处还是可以考虑到 UITableView 的,当然是特殊的 UITableView。


一、小尝试,解决多种点击(样式相同)

之前我们在做个人页面的时候,就是如上图微信中的个人页面一样,样式相同有多种点击 ,我们之前组长封装了一个方便点击,样式可调的工具。

  • 数据处理, 可以通过自己建立模型,给予分类。
SettingArrowItem *oneItem = [SettingArrowItem itemWithIcon:@"test_icon" title:@"First" destVcClass:[FirstViewController class]];
SettingArrowItem *twoItem = [SettingArrowItem itemWithIcon:@"test_icon" title:@"Second" destVcClass:[SecondViewController class]];

SettingGroup *groupOne = [[SettingGroup alloc] init];
groupOne.items = [NSMutableArray arrayWithArray:@[oneItem,twoItem]];
[self.dataArray addObject:groupOne];
  • 点击,相当于之前已经做好选择了,当然这样的应用场景比较固定,也不利于扩展。
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    // 1.模型数据
    SettingGroup *group = self.dataArray[indexPath.section];
    SettingItem *item = group.items[indexPath.row];
    // 2、箭头可以点击
    if ([item isKindOfClass:[SettingArrowItem class]]) {
        SettingArrowItem *arrowItem = (SettingArrowItem *)item;
        // 如果没有需要跳转的控制器
        if (arrowItem.destVcClass == nil) return;
        UIViewController *vc = [[arrowItem.destVcClass alloc] init];
        vc.title = arrowItem.title;
        [self.navigationController pushViewController:vc animated:YES];
    }
}

这一种处理,相当于是简单的封装数据,让点击时更方便,当然一些小部分的Cell 样式也是可以任意改变的,然而还是认为应用场景有限,只能针对于Account 页面的点击,如微信那个人界面。

二、尝试,解决多种样式,多种点击(样式不同,点击不同)

这是我们组长为更好的用 UITableView 特意做的一个数据管理器,ZHTableViewGroup,虽说有些细节处理不是很认同,特别是 Demo 中某两处小细节,同时 Demo 也没有呈现chu,但整体来说思路是很棒的,使用也是很方便的。

  • 数据处理,此处的点击事件,已经放出来啦,样式也是随时可以改变啦
ZHTableViewGroup *group = [[ZHTableViewGroup alloc]init];
ZHTableViewCell *cellOne = [[ZHTableViewCell alloc]initWithTableView:self.homeTableView range:NSMakeRange(0, 6) cellHeight:44 cellClass:[HomeCellStyleOne class] identifier:KHomeCellStyleOneIdentifier];
cellOne.configCellComplete = ^(UITableViewCell *cell, NSIndexPath *indexPath) {
    HomeCellStyleOne *cellOne = (HomeCellStyleOne *)cell;
    cellOne.textLabel.text = @"One Title";
    cellOne.detailTextLabel.text = @"One Detail";
};
cellOne.didSelectRowComplete = ^(UITableViewCell *cell, NSIndexPath *indexPath) {
    NSLog(@"cell->%@,indexPath->%@",cell,indexPath);
};
[group addTableViewCell:cellOne];

ZHTableViewCell *cellTwo = [[ZHTableViewCell alloc]initWithTableView:self.homeTableView range:NSMakeRange(6, 5) cellHeight:44 cellClass:[HomeCellStyleTwo class] identifier:KHomeCellStyleOneIdentifier];
cellTwo.configCellComplete = ^(UITableViewCell *cell, NSIndexPath *indexPath) {
    HomeCellStyleOne *cellTwo = (HomeCellStyleOne *)cell;
    cellTwo.textLabel.text = @"Two Title";
    cellTwo.detailTextLabel.text = @"Two Detail";
};
cellTwo.didSelectRowComplete = ^(UITableViewCell *cell, NSIndexPath *indexPath) {
    NSLog(@"cell->%@,indexPath->%@",cell,indexPath);
};

[group addTableViewCell:cellTwo];
[self.dataSource addTableV
  • 而代理,一如既往是照旧,只是需要固定一些写法。
#pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return self.dataSource.sectionNumber;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    ZHTableViewGroup *group = [self.dataSource groupWithIndex:section];
    return group.rowNumber;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    ZHTableViewGroup *group = [self.dataSource groupWithIndex:indexPath.section];
    UITableViewCell *cell = [group cellWithIndexPath:indexPath];
    return cell;
}

#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    ZHTableViewGroup *group = [self.dataSource groupWithIndex:indexPath.section];
    [group didSelectRowAtIndexPath:indexPath];
}

  • 关键方法:
/*!
 *  @brief 初始化cell托管的对象
 *
 *  @param tableView  cell所注册的tableview
 *  @param range      cell的范围
 *  @param cellHeight cell的高度
 *  @param cellClass  注册cell的class
 *  @param identifier 注册cell的标识符
 *
 *  @return ZHTableViewCell
 */
- (instancetype)initWithTableView:(UITableView *)tableView range:(NSRange)range cellHeight:(CGFloat)cellHeight cellClass:(Class)cellClass identifier:(NSString *)identifier;

此处,有很多细节方面,我不是很赞同其处理,例如 range Cell 的范围,当然此种方式已经能满足我们大部分的场景的(不是统一数据的类型那种)。

另外,类命名也不认同, ZHTableViewCell 是属于一个 Manager 的,不应该直接命名为 Cell 结尾,容易让人误解。

三、看 《RETableViewManager》

于是我先去看看 RETableViewManager ,希望可以解决一些疑惑。这个轮子就是为了解决多种样式多种点击的列表。

直接看一下其 最基本用法:

- (void)viewDidLoad {
    [super viewDidLoad];
    // 总的 Manager
    self.manager = [[RETableViewManager alloc] initWithTableView:self.tableView];
    // Section 
    RETableViewSection *section = [RETableViewSection sectionWithHeaderTitle:@"Test"];
    [self.manager addSection:section];
    // Cell Item (基本的 Item)
    RETableViewItem *customItem = [RETableViewItem itemWithTitle:@"String cell" accessoryType:UITableViewCellAccessoryDisclosureIndicator selectionHandler:^(RETableViewItem *item) {
        NSLog(@"Test: %@", item);
    }];
    // Section Add Item
    [section addItem:customItem];
}

大致可以了解到 Cell ,Section 通通都由一个 RETableViewManager 来整体管理,而且 Cell 处的点击和样式都是单独控制的,低耦合高内聚,这样可以任意添加 Cell(此处的 Cell 都是基于其自定义的Cell),此处我的想法是自己是否也可以这样做呢?当然 Cell 是任意的,并不要遵循某个BaseCell。

四、理解改善

其实ZHTableViewGroup 已经可以说对其样式和对其点击已经抽离出来了,但可以对 ZHTableViewGroup 进行三点改善,当然也是可商榷的。

  • 1、类命名更规范,将 ZHTableViewCell ==> ZHTableViewManager 相对来说更正确。
  • 2、将 Rang 抽离出来,这样更利于理解和更利于优化。
    如果不写,就是直接按照顺序,一步一步添加上去,默认顺序
  • 3、group 分组,实际还是可以盖上成当真的分组时,自动有空行空出来,实际上换句话说就是可以说此处的结构还可以优化。

晋级: 将高度自适应,暂时没进行,但是可以尝试,不过从另一个角度来说,通常如果类似我想应用的场景,一般高度都是固定的,所以也没必要,否则这个场景页面就不知道什么情况啦。

例如:下面是我将其 Rang 取消后一个 Cell 往一个 Cell 的结果

@implementation ZHTableViewCell {
    NSRange _tempRange;
    UITableView *_tableView;
}

static NSUInteger number = 0;

- (instancetype)initWithTableView:(UITableView *)tableView cellHeight:(CGFloat)cellHeight cellClass:(Class)cellClass identifier:(NSString *)identifier {
    if (self = [super init]) {
        NSParameterAssert(tableView);
        NSParameterAssert(identifier);
        _tableView = tableView;
        NSDictionary *cellClassDict = [tableView valueForKey:@"_cellClassDict"];
        __block BOOL isExitRegister = NO;
        [cellClassDict.allKeys enumerateObjectsUsingBlock:^(NSString *  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            if ([obj isEqualToString:identifier]) {
                isExitRegister = YES;
            }
        }];
        if (!isExitRegister) {
            [tableView registerClass:cellClass forCellReuseIdentifier:identifier];
        }
        _tempRange = NSMakeRange(number, 1);
        number++;
        // _range = range;
        _cellHeight = cellHeight;
        _identifier = identifier;
    }
    return self;
}

- (BOOL)cellIsExitRangeWithIndex:(NSUInteger)index {
   // return NSLocationInRange(index, _range);
    return NSLocationInRange(index, _tempRange);
}

- (UITableViewCell *)cellWithIndexPath:(NSIndexPath *)indexPath {
    return [_tableView dequeueReusableCellWithIdentifier:_identifier forIndexPath:indexPath];
}

@end

此处这样改完后,又发现没必要,一步一步加上去虽说好用,但是脱离出来其实也没必要,只是老觉的这样一连串参数初始化 感觉怪怪的。

如后期继续扩展维护,写法和规范像 RETableViewManager 学习是必要的。

PS : 目前ZHTableViewGroup 上传的 DEMO 还有问题,仔细看就知道了,哈哈。

五、知识点

  • _cellClassDict 作为 UITableView 的私有变量,保存 cellClass 和 cellIden 用的。

  • NSLocationInRange

NS_INLINE BOOL NSLocationInRange(NSUInteger loc, NSRange range) {
    return (!(loc < range.location) && (loc - range.location) < range.length) ? YES : NO;
}

类似这样的内敛,有时效果还是很巧妙的

  • 当然更多的是对 UITableView 的熟悉度更加深了。


    效果图

类似一连串的 View 的布局,我们就还是可以采用 UITableView, 可以解决上述淘宝 home 首页那样的问题,让每一排 View 当做一个 Cell, 实现起来还是很方便的。

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

推荐阅读更多精彩内容

  • 概述在iOS开发中UITableView可以说是使用最广泛的控件,我们平时使用的软件中到处都可以看到它的影子,类似...
    liudhkk阅读 8,993评论 3 38
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,029评论 4 62
  • 1.form表单有什么作用?有哪些常用的input 标签,分别有什么作用? 表单的作用是搜集用户的输入,用户提交表...
    CYC_dc68阅读 391评论 0 0
  • 只是你不知道而已
    驭临风阅读 192评论 0 1
  • 1.运营课程给我带来最初的印象和思考 我在知道需要完成这么一次学习实践,开始的我还是比较逃避的,通过三节课的课程学...
    时光听得见阅读 239评论 0 0