UITableView

这里写图片描述

//cell右边视图类型 >
这里写图片描述
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;

添加一行

这里写图片描述
//代理方法

//返回cell的类型
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
    return UITableViewCellEditingStyleInsert;
}
//如图当点击左边绿色加号的时候触发此方法
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
    if (editingStyle ==UITableViewCellEditingStyleInsert ) {
//先插入数据
[self.dataModel insertRowAtIndexPath:indexPath];
//开始加载
[tableView beginUpdates];
[tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
//结束加载
[tableView endUpdates];
//所有数据会被重新加载一次,有点耗时
//[tableView reloadData];
    }
}

删除一行

这里写图片描述
//删除也是下面两个代理方法,比较简单

//返回cell的样式
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
    return UITableViewCellEditingStyleDelete;
}
//当点击右边的删除时触发此方法
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        NSLog(@"h2");
        //先更新数据
        [self.dataModel removeRowAtIndexPath:indexPath];
        [tableView beginUpdates];
        //再更新界面
        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
        [tableView endUpdates];
    }

}
//测试,增加、删除状态下此方法不会被执行,因为此时tableview处于编辑状态下cell不具有选择状态,跟cell 的style相关
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    NSLog(@"h1");
}
//返回右边删除按钮自定义标题
-(NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath{
    return @"删除";
}

删除多行

这里写图片描述
//代理方法

//返回cell的类型
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
    return UITableViewCellEditingStyleDelete|
    UITableViewCellEditingStyleInsert;
}
//此方法用于把选中的cell行号保存在一个临时数组中
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    //选中时保存
    [_selectedIndexPaths addObject:indexPath];
}
//此方法用于把选中之后再取消的cell行号从临时数组中去除
-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath{
    //取消时移除
    [_selectedIndexPaths removeObject:indexPath];
}

这里写图片描述

//重写父类方法,此方法当点击右边按钮时触发,用于把数据和多行cell一次性删除
-(void)rightButtonHandle:(UIBarButtonItem *)item{
    [super rightButtonHandle:item];
    //判断tableView是否处于编辑状态
    if (self.tableView.editing) {
        [_selectedIndexPaths removeAllObjects];
    }else{
        //注意:删除时应该倒序删除
        [self.dataModel removeRowsAtIndexPaths:_selectedIndexPaths];
//        [self.tableView beginUpdates];
        [self.tableView deleteRowsAtIndexPaths:_selectedIndexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
//      [self.tableView endUpdates];
        [self.tableView reloadData];
    }
}

//下面方法是对后台数据的删除

-(void)removeRowsAtIndexPaths:(NSArray *)indexPaths{
//删除数据前需要对数组进行排序,以便后序删除
NSArray *array = [indexPaths sortedArrayUsingSelector:@selector(compare:)];
    //倒序删除
    for (NSInteger i=array.count-1;i>=0;i--) {
        [self removeRowAtIndexPath:array[i]];
    }
}

移动cell

这里写图片描述
//代理方法

//返回cell类型
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
    return UITableViewCellEditingStyleNone;
}
//移动触发的代理方法
-(void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath{
//如果前后位置相同,则不移动
    if ([sourceIndexPath isEqual:destinationIndexPath]) {
        return;
    }
    [self.dataModel moveRowAtIndexPath:sourceIndexPath toIndexPath:destinationIndexPath];
// 跨区移动会崩溃,无需手动刷新页面,会自动刷新
//    [self.tableView moveRowAtIndexPath:sourceIndexPath toIndexPath:destinationIndexPath];

}

下面的两个功能实现比较麻烦,特别是最后一个

展开关闭

这里写图片描述
//用于记录每个区的开关状态,0:关 1:开

    NSMutableArray *_sectionsStatus;

//代理方法

//此方法返回headerView的高度,赋予headerView状态,block动态改变headerView状态,并且此方法调用较多,每次点击headerView都会局部刷新section从而调用此方法
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
    return 44.0;
}
//此方法用于返回headerView,
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
    CGRect frame = CGRectMake(0, 0, VIEW_WIDTH, 44);
    SectionHeaderView *headerView = [[SectionHeaderView alloc] initWithFrame:frame];
    //获取区的标题
    NSString *sectionTitle = [self.dataModel titleOfSection:section];
    BOOL status = [_sectionsStatus[section] boolValue];
    //头视图更新标题及图片
    [headerView updateWithTitle:sectionTitle status:status];
    headerView.block = ^{
        //改变开关状态
        [_sectionsStatus replaceObjectAtIndex:section withObject:@(!status)];
        //局部刷新section,从而循环调用此方法,赋予headerView状态
        [tableView reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationAutomatic];
    };
    return [headerView autorelease];
}
//每次局部刷新section调用此方法,从而返回cell个数
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    if ([_sectionsStatus[section] isEqualToNumber:@0]) {
        return 0;
    }
    return [self.dataModel numberOfRowsInSection:section];
}

搜索cell

未操作

这里写图片描述

这里写图片描述

//搜索相关的变量
{
    //搜索框
    UISearchBar *_searchBar;
    //搜索控制器,不过已被UISearchController替代
    UISearchDisplayController *_searchDC;
    //搜索结果保存在数组中
    NSMutableArray *_searchResult;
}

//创建搜索框

- (void)createSearchBar
{
    //先修改tableView的frame
    CGRect frame = self.tableView.frame;
    frame.origin.y += 44;
    frame.size.height -= 44;
    self.tableView.frame = frame;
    //设置searchBar
    _searchBar = [[UISearchBar alloc] init];
    _searchBar.frame = CGRectMake(0, 64, VIEW_WIDTH, 44);
    _searchBar.placeholder = @"搜索偶像";
    //显示右边cancel按钮
    _searchBar.showsCancelButton = YES;

    //设置代理
    _searchBar.delegate = self;

    [self.view addSubview:_searchBar];
}

//设置_searchDC

- (void)createSearchDisplayController
{
    //创建UISearchDisplayController并绑定searchBar
    //以及搜索结果要显示的视图控制器
    _searchDC = [[UISearchDisplayController alloc] initWithSearchBar:_searchBar contentsController:self];
    //设置搜索结果的tableView的代理
    _searchDC.searchResultsDataSource = self;
    _searchDC.searchResultsDelegate = self;
    //注册搜索结果的tableView的复用标识及cell类型
    [_searchDC.searchResultsTableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"searchCellId"];
}

//searchBar的代理方法
这里写图片描述

//编辑时隐藏导航栏、状态栏
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
{
    //隐藏状态栏及导航条
    [self.navigationController setNavigationBarHidden:YES animated:YES];
    [self setNeedsStatusBarAppearanceUpdate];

    //动画向上偏移64
    [UIView animateWithDuration:0.5 animations:^{
        _searchBar.transform = CGAffineTransformMakeTranslation(0, -64);
    }];
}

这里写图片描述

//点击cancel按钮结束编辑时调用方法显示导航条和状态栏
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar
{
    //显示状态栏及导航条
    [self.navigationController setNavigationBarHidden:NO animated:YES];
    [self setNeedsStatusBarAppearanceUpdate];

    //还原transform
    [UIView animateWithDuration:0.3 animations:^{
        _searchBar.transform = CGAffineTransformIdentity;
    }];
}

这里写图片描述

//进行编辑时调用此方法,每次change都会调用
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
    _searchResult.array = [self.dataModel searchWithText:searchText];
}
//当点击cancel按钮时会调用此方法,隐藏键盘
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
    [_searchBar resignFirstResponder];
}

//下面代理方法是重写父类代理方法,用于区分时是searchDC返回的tableView还是self.tableView,从而控制数据的显示

#pragma mark - UITableViewDataSource
//返回section数
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    if (tableView == self.tableView) {
        return [super numberOfSectionsInTableView:tableView];
    } else if (tableView == _searchDC.searchResultsTableView) {
        return 1;
    }
    return 0;
}
//返回cell行数
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if (tableView == self.tableView) {
        return [super tableView:tableView numberOfRowsInSection:section];
    } else if (tableView == _searchDC.searchResultsTableView) {
        return _searchResult.count;
    }
    return 0;
}
//返回cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (tableView == self.tableView) {
        return [super tableView:tableView cellForRowAtIndexPath:indexPath];
    } else if (tableView == _searchDC.searchResultsTableView) {
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"searchCellId"];
        cell.textLabel.text = _searchResult[indexPath.row];
        return cell;
    }
    return nil;
}

UITableViewCell基本属性

这里写图片描述
此代理方法会在每次tableview布局时首先执行,如果返回值为0,则不会执行下面的代理方法
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.dataSource.count;
}
两种复用cell的方法:
1. 这种复用如果复用池里不存在复用的对象,则不自动创建cell对象,由用户手动创建想要的类型,所以前面不需要注册cell
ITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@”cell”];

  1. 这种复用如果复用池中不存在复用的对象,系统则根据前面注册的cell类型自动创建cell,所以前面需要注册
    [tableView dequeueReusableCellWithIdentifier:@”cell” forIndexPath:indexPath];
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cellId"];
    if (!cell) {
    /*      风格                      详情          图片
     UITableViewCellStyleDefault     不支持        支持
     UITableViewCellStyleValue1       支持         支持
     UITableViewCellStyleValue2       支持        不支持
     UITableViewCellStyleSubtitle 在textLabel下    支持
     */
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cellId"];
    }
    //textLabel
    cell.textLabel.text = [NSString stringWithFormat:@"第%.2ld行",indexPath.row+1];
    //detailTextLabel
    cell.detailTextLabel.text = @"详情";
    //imageView
    cell.imageView.image = [UIImage imageNamed:@"colors"];

    /*右边附加视图式样
     UITableViewCellAccessoryDisclosureIndicator    >
     UITableViewCellAccessoryDetailDisclosureButton ¡>
     UITableViewCellAccessoryCheckmark              √
     UITableViewCellAccessoryDetailButton           ¡
    */
    cell.accessoryType = UITableViewCellAccessoryDetailButton;
    cell.editingAccessoryType = UITableViewCellAccessoryCheckmark;
    //设置自定义附加视图,accessoryType无效
    UIImageView *normalView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"next.jpg"]];
    cell.accessoryView = [normalView autorelease];
    UIImageView *editingView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"prev.jpg"]];
    cell.editingAccessoryView = [editingView autorelease];

    //背景色
    cell.backgroundColor = [UIColor greenColor];
    //包含视图背景色
    cell.contentView.backgroundColor = [UIColor colorWithRed:RandomValue green:RandomValue blue:RandomValue alpha:1.0];
    /*选中风格
     UITableViewCellSelectionStyleNone,     无效
     UITableViewCellSelectionStyleBlue,     浅灰
     UITableViewCellSelectionStyleGray,     浅灰
     UITableViewCellSelectionStyleDefault   浅灰
     */
    cell.selectionStyle = UITableViewCellSelectionStyleDefault;
    //设置选中视图,frame无效,只有颜色有效
    UIView *backView = [[UIView alloc] init];
    backView.backgroundColor = [UIColor redColor];
    cell.selectedBackgroundView = backView;
    [backView release];

    return cell;
}
//附加视图按钮(带button风格)点击回调方法
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"click%ld", indexPath.row);
}

动态返回cell的高度

//heightForRowAtIndexPath的调用优先于cellForRowAtIndexPaht,调用的次数跟行数相同,目的是先计算tableView的内容大小
//如果在这里调用cellForRowAtIndexPath 会导致所有的cell先构建一遍,效率低
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    CommonModel *model = [self.dataSource objectAtIndex:indexPath.row];
    //以下写法不推荐
//    UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
//    [cell calculateCellHeight:model];
    //通常在cell中写一个类方法来完成计算cell的高度问题
    return [CommonTableViewCell cellHeightForModel:model];
}

锚点、cell3D旋转

//在cell显示前,改变cell的锚点,设置动画进行旋转

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    //先保存frame
    CGRect frame = cell.frame;
    //锚点(旋转的中心点),默认是(0.5,0.5)
    cell.layer.anchorPoint = CGPointMake(0, _isDownward);
    //锚点在父视图中的坐标
    cell.layer.position = CGPointMake(frame.origin.x, frame.origin.y+_isDownward*frame.size.height);
    char flag = _isDownward ? -1 : 1;
    cell.layer.transform = CATransform3DMakeRotation(flag*M_PI_2, 0, 0, 1);
    [UIView animateWithDuration:1 animations:^{
        cell.layer.transform = CATransform3DIdentity;
    }];
}

自定义cell

这里写图片描述
//定制cell需要继承UITableViewCell
//默认创建cell时调用的方法,所以定制时需要重写
//在此方法中把定制的内容添加到self.contentView上面,不进行布局

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier;
//粘贴视图,若添加到self上编辑时会出现覆盖
[self.contentView addSubview:_iconView];
[self.contentView addSubview:_titleLabel];

//下面的方法对添加的视图进行布局,自动调用

//在布局时会自动调用,不能手动调用,
//若想手动更新,调用[self layoutIfNeeded];
- (void)layoutSubviews
{
    [super layoutSubviews];

    CGSize size = self.contentView.frame.size;
    ......
}

//下面方法是自己定义的方法,用于外部赋予数据

- (void)updateWithDataModel:(BookModel *)book{}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在UITableView的section中添加数据,你需要先创建一个包含所需数据的数组。然后,在UITableViewDataSource协议中实现以下方法: 1. numberOfSections(in tableView: UITableView) -> Int:返回表格中的section数。 2. tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int:返回指定section中的行数。 3. tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell:返回指定indexPath的UITableViewCell实例。 例如,假设你有一个包含多个section的UITableView,每个section都包含一个字符串数组。以下是一个示例代码: ``` class ViewController: UIViewController, UITableViewDataSource { var data: [[String]] = [["item 1", "item 2"], ["item 3", "item 4", "item 5"]] @IBOutlet weak var tableView: UITableView! override func viewDidLoad() { super.viewDidLoad() tableView.dataSource = self } // MARK: - UITableViewDataSource func numberOfSections(in tableView: UITableView) -> Int { return data.count } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return data[section].count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) cell.textLabel?.text = data[indexPath.section][indexPath.row] return cell } } ``` 在这个例子中,我们创建了一个包含两个section的UITableView。每个section都有一个字符串数组,我们将其存储在data数组中。在numberOfSections方法中,我们返回data数组的数量,即section的数量。在tableView(_:numberOfRowsInSection:)方法中,我们返回特定section中的行数。最后,在tableView(_:cellForRowAt:)方法中,我们获取特定indexPath的字符串并将其显示在UITableViewCell中。 注意,在上述示例代码中,我们将UITableViewCell标识符设置为“Cell”,你需要确保在Storyboard或xib文件中对应的UITableViewCell的标识符也设置为“Cell”。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值