iOS 界面布局

iOS 中 UITableView 某个场景的使用

2016-12-20  本文已影响264人  天空中的球

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

多种样式,多种点击的列表
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    switch (indexPath.row) {
        case 0: {
            
        }
            break;
        default:
            break;
    }
}

复杂的 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 进行三点改善,当然也是可商榷的。

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

例如:下面是我将其 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 还有问题,仔细看就知道了,哈哈。

五、知识点

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

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

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

上一篇下一篇

猜你喜欢

热点阅读