UITableView的使用(UITableViewCell\section页眉\section页脚复用、sectionHeaderView点击效果)

这篇博客详细介绍了UITableView的使用,包括其作为UIScrollView子类的滚动特性、设置UITableViewStyle的注意事项、必须实现的UITableViewDelegate和UITableViewDataSource代理方法。特别强调了复用技术,如UITableViewCell的复用以及section页眉和页脚的复用。同时提到了section页眉视图的点击效果实现,指出在设置title与view时要避免冲突。

UITableView是列表视图,类似于QQAPP中联系人页面的功能。

UITableViewUIScrollView的子类,默认拥有UIScrollView的滚动功能,而不用设置contentSize

使用注意事项

1必须添加协议,以及实现代理方法

1-1 UITableViewDelegate   视图代理

1-2 UITableViewDataSource 数据源代理

2 初始化时,必须使用方法 - (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style

3 列表类型UITableViewStyle设置时,注意差异,如:

3-1 UITableViewStyleGrouped,如果有多个section时,当前section页眉不会在最顶端显示

3-2 UITableViewStylePlain,如果有多个section时,当前section页眉会在最顶端显示

4代理方法实现中,注意相同功能代理方法实现的冲突,如:

4-1 - (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section - (nullable UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section不能同时设置

4-2 - (nullable NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section - (nullable UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section不能同时设置

5、注意复用技术

5-1 UITableViewCell的复用

5-2 每个section中页眉视图的复用

5-3 每个section中页脚视图的复用


@interface ViewController () <UITableViewDataSource, UITableViewDelegate>

@property (nonatomic, strong) UITableView *tableview;
@property (nonatomic, strong) NSMutableArray *mainArray; // 数据源
@property (nonatomic, strong) NSMutableArray *boolArray; // 用于控制section行数的数据源,即控制section的展开,或折叠

@end

// 设置数据源
NSInteger sectionCount = arc4random() % 10 + 1; // 随机数
sectionCount = 10;
self.mainArray = [[NSMutableArray alloc] init];
for (int i = 0; i < sectionCount; i++)
{
        NSInteger rowCount = arc4random() % 10 + 1; // 随机数
        rowCount = 10;
        NSMutableArray *array = [NSMutableArray arrayWithCapacity:rowCount];
        for (int j = 0; j < rowCount; j++)
        {
            NSString *rowText = [NSString stringWithFormat:@"section(%@)-row(%@)", @(i + 1), @(j + 1)];
            [array addObject:rowText];
        }
        NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
        [dict setObject:[NSString stringWithFormat:@"section(%@)", @(i + 1)] forKey:@"title"];
        [dict setObject:array forKey:@"array"];
        
        [self.mainArray addObject:dict];
}

self.boolArray = [[NSMutableArray alloc] init];
for (int i = 0; i < sectionCount; i++)
{
        // 1为展开,0为折叠
        [self.boolArray addObject:@(1)];
}


self.tableview = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
[self.view addSubview:self.tableview];
self.tableview.backgroundColor = [UIColor redColor];
    
/*
设置代理
1 设置实现代理方法的对象
2 添加协议
3 实现代理方法
*/
self.tableview.delegate = self;
self.tableview.dataSource = self;

// 其他属性
// 头部视图
UIImageView *headerView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, CGRectGetWidth(self.view.bounds), 200.0)];
headerView.image = [UIImage imageNamed:@"headerImage"];
self.tableview.tableHeaderView = headerView;
// 尾部视图
UIImageView *footerView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, CGRectGetWidth(self.view.bounds), 200.0)];
footerView.image = [UIImage imageNamed:@"footerImage"];
self.tableview.tableFooterView = footerView;
// 滚动回顶端,即点击状态栏视图时,自动滚动回顶端,默认YES,即打开
self.tableview.scrollsToTop = YES;
// UITableViewCell中分割线的颜色
self.tableview.separatorColor = [UIColor purpleColor];
// UITableViewCell中分割线样式,默认单条线,即UITableViewCellSeparatorStyleSingleLine
self.tableview.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
// UITableViewCell中分割线对齐,默认有间距(注意:与UITableViewCell的 separatorInset、layoutMargins 属性同时设置才有效)
self.tableview.separatorInset = UIEdgeInsetsMake(0.0, 0.0, 0.0, 0.0);
self.tableview.layoutMargins = UIEdgeInsetsMake(0.0, 0.0, 0.0, 0.0);

// UITableViewDataSource

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    // 总共有多少个section,默认是1个
    
    NSInteger count = self.mainArray.count;
    return count;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // 每个section有多少个row
    
    NSDictionary *dict = self.mainArray[section];
    NSArray *array = [dict objectForKey:@"array"];
    NSInteger count = 0;
    NSNumber *openNumber = self.boolArray[section];
    if (openNumber.intValue == 1)
    {
        count = array.count;
    }
    
    return count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 每个row中具体视图UITableViewCell
    
    // 复用标识符
    static NSString *const identifier = @"UITableViewCell";
    // 未复用标识
//    NSString *identifier = [NSString stringWithFormat:@"%@", indexPath];
    
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
    if (cell == nil)
    {
        /*
         注意:
         实例化时样式为 UITableViewCellStyleSubtitle 时在主标题下面显示,图标在左边显示
         实例化时样式为 UITableViewCellStyleSubtitle 时在主标题下面显示,图标在左边显示
         实例化时样式为 UITableViewCellStyleValue1 时在主标题右边显示,图标在左边显示
         实例化时样式为 UITableViewCellStyleDefault 时不显示副标题,图标在左边显示
         */
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier];
        
        
        // 设置分割线对齐(注意:与tableview的 separatorInset、layoutMargins 属性同时设置才有效)
        cell.separatorInset = UIEdgeInsetsMake(0.0, 0.0, 0.0, 0.0);
        cell.layoutMargins = UIEdgeInsetsMake(0.0, 0.0, 0.0, 0.0);
        // 选中时的状态
        cell.selectionStyle = UITableViewCellSelectionStyleGray;
        // 设置自定义事件图标(在右侧显示。注意:accessoryType 与 accessoryView 不能同时设置)
        UIImageView *accessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cellImage"]];
        accessoryView.frame = CGRectMake(0.0, 0.0, 20.0, 20.0);
        cell.accessoryView = accessoryView;
        // 设置系统副件图标(在右侧显示。注意:accessoryType 与 accessoryView 不能同时设置)
        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    }
    
    
    NSDictionary *dict = self.mainArray[indexPath.section];
    NSArray *array = [dict objectForKey:@"array"];
    NSString *text = [array objectAtIndex:indexPath.row];

    
    // 设置cell中的图标
    cell.imageView.image = [UIImage imageNamed:@"cellImage"];
    // 设置cell中的主标题
    cell.textLabel.text = text;
    // 设置cell中的副标题,在主标题下面显示
    /*
     注意:
     实例化时样式为 UITableViewCellStyleSubtitle 时在主标题下面显示,图标在左边显示
     实例化时样式为 UITableViewCellStyleSubtitle 时在主标题下面显示,图标在左边显示
     实例化时样式为 UITableViewCellStyleValue1 时在主标题右边显示,图标在左边显示
     实例化时样式为 UITableViewCellStyleDefault 时不显示副标题,图标在左边显示
    */
    cell.detailTextLabel.text = @"ios learning";
    
    
    return cell;
}


//- (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
//{
//    // 每个section中的页眉视图的标题
//    // 设置后不能再设置 - (nullable UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
//    
//    NSString *title = [NSString stringWithFormat:@"header section %@", @(section)];
//    return title;
//}
//
//- (nullable NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
//{
//    // 每个section中的页脚视图的标题
//    // 设置后不能再设置 - (nullable UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
//    
//    NSString *title = [NSString stringWithFormat:@"footer section %@", @(section)];
//    return title;
//}

// UITableViewDelegate

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 每个section中每个row的视图UITableViewCell的高度。默认是44.0
    
    return 44.0;
}

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    // 每个section中页眉的高度
    
    return 50.0;
}

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
    // 每个section中页脚的高度
    
    return 20.0;
}

- (nullable UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    // 设置每个section的页眉视图
    // 设置后不能再设置 - (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
    
    
    NSDictionary *dict = self.mainArray[section];
    NSString *title = [dict objectForKey:@"title"];
    
    
    // 未复用
//    UIButton *view = [[UIButton alloc] initWithFrame:CGRectMake(0.0, 0.0, CGRectGetWidth(self.view.bounds), 50.0)];
//    view.backgroundColor = [UIColor brownColor];
//    [view setTitle:title forState:UIControlStateNormal];
//    [view setTitleColor:[UIColor redColor] forState:UIControlStateHighlighted];
//    
//    view.tag = 1000 + section;
//    [view addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
//    
//    return view;
    
    // 复用
    static NSString *const identifier = @"headerview";
    
    UITableViewHeaderFooterView *headerview = [tableView dequeueReusableHeaderFooterViewWithIdentifier:identifier];
    if (headerview == nil)
    {
        headerview = [[UITableViewHeaderFooterView alloc] initWithReuseIdentifier:identifier];
        
        UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(10.0, 10.0, (CGRectGetWidth(self.view.bounds) - 10.0 * 2), 30.0)];
        button.backgroundColor = [UIColor brownColor];
        [button setTitleColor:[UIColor redColor] forState:UIControlStateHighlighted];
        button.tag = 2000;
        
//        button.tag = 1000 + section;
        [button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
        
        [headerview.contentView addSubview:button];
    }
    
    headerview.contentView.tag = 1000 + section;
    NSLog(@"headerview.tag = %@", @(headerview.tag));
    
    UIButton *button = (UIButton *)[headerview.contentView viewWithTag:2000];
    [button setTitle:title forState:UIControlStateNormal];
    
    return headerview;
    
}

- (nullable UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
    // 设置每个section的页脚视图
    // 设置后不能再设置 - (nullable NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
    
    
    NSDictionary *dict = self.mainArray[section];
    NSString *title = [dict objectForKey:@"title"];
    
    
    // 未复用
//    UILabel *view = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, CGRectGetWidth(self.view.bounds), 20.0)];
//    view.backgroundColor = [UIColor yellowColor];
//    view.text = title;
//    
//    return view;
    
    // 复用
    static NSString *const identifier = @"footerview";
    
    UITableViewHeaderFooterView *footerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:identifier];
    if (footerView == nil)
    {
        footerView = [[UITableViewHeaderFooterView alloc] initWithReuseIdentifier:identifier];
        
        UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10.0, 0.0, (CGRectGetWidth(self.view.bounds) - 10.0 * 2), 20.0)];
        label.backgroundColor = [UIColor greenColor];
        label.tag = 2000;
        
        [footerView.contentView addSubview:label];
    }
    
    UILabel *label = (UILabel *)[footerView.contentView viewWithTag:2000];
    label.text = title;
    
    return footerView;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    // UITableViewCell单元格选中点击
    
    // 取消高亮选中状态
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    
    NSLog(@"你点击了 第 %@ 个section中的第 %@ 个row", @(indexPath.section + 1), @(indexPath.row + 1));
}

// 响应方法 用于展开,或折叠section
- (void)buttonClick:(UIButton *)button
{
//    NSInteger section = button.tag - 1000;
    UIView *superview = button.superview;
    NSInteger tagSuperview = superview.tag;
    NSInteger section = tagSuperview - 1000;
    
    NSNumber *openNumber = self.boolArray[section];
    if (openNumber.intValue == 1)
    {
        [self.boolArray replaceObjectAtIndex:section withObject:@(0)];
    }
    else
    {
        [self.boolArray replaceObjectAtIndex:section withObject:@(1)];
    }
    
    // 重新刷新数据
    // 方法1 刷新全总数据
//    [self.tableview reloadData];
    // 方法2 只刷新改变的secton
    NSIndexSet *reloadIndexSet = [NSIndexSet indexSetWithIndex:section];
    [self.tableview reloadSections:reloadIndexSet withRowAnimation:UITableViewRowAnimationNone];
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

番薯大佬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值