零基础iOS开发学习日记-控制器篇-UITableViewController

853 阅读5分钟

开头

UITableViewController

实际用处

  • 微博推文界面
  • 微信、QQ的好友界面,聊天界面
  • 新闻界面
  • 只要是界面上需要列举内容,而且每块内容需要的数据,都大致相同,就可以用到

基础用法

  • UITableViewController数据的加载也是通过UITableViewDataSource的代理方法实现的
  • 头尾也可以返回
//组数
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 2;
}
//组内行数
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 5;
}
//cell样式
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
    cell.textLabel.text = @"test";
    return cell;
}
//头
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    return [NSString stringWithFormat:@"Header%ld", section];
}
//尾
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
    return [NSString stringWithFormat:@"Footer%ld", section];
}

UITableView

表单样式

UITableViewStylePlain //表头和表尾是悬浮的
UITableViewStyleGrouped //常用,表头和表尾可以随界面滚动
UITableViewStyleInsetGrouped //内嵌样式
  • 设置UITableViewController的表单样式
- (instancetype)initWithStyle:(UITableViewStyle)style {
    return [super initWithStyle:UITableViewStyleInsetGrouped];
}
  • 在界面上添加UITableView
self.view = [[UITableView alloc] initWithFrame:[UIScreen mainScreen].bounds style:UITableViewStyleGrouped];

一些设置

  • 设置分割线
UITableViewCellSeparatorStyleNone,
UITableViewCellSeparatorStyleSingleLine,
self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
  • 分割线颜色
self.tableView.separatorColor = [UIColor redColor];
  • 渲染颜色
self.tableView.tintColor = [UIColor orangeColor];

数据刷新

  • 当遇到更新表单中的数据时,需要数据刷新
//刷新全部
[self.tableView reloadData];
//刷新某一组
NSIndexSet *idxSet = [NSIndexSet indexSetWithIndex:1];
[self.tableView reloadSections:idxSet withRowAnimation:UITableViewRowAnimationFade];
//刷新某一行
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:2 inSection:1];
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];

UITableViewCell

  • 在实际开发中,UITableViewCell一般是自定义的,但是要求不高的时候也会选择用系统的cell类型
UITableViewCellStyleDefault //图片+标题
UITableViewCellStyleValue1 //图片+标题+右注释
UITableViewCellStyleValue2 //标题+左注释
UITableViewCellStyleSubtitle //图片+标题+下注释

基本设置

UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:nil];
cell.textLabel.text = @"test";
cell.imageView.image = [UIImage imageNamed:@"dv_icon1"];
cell.detailTextLabel.text = @"detail";

一些设置

  • 指示符
cell.accessoryType = UITableViewCellAccessoryDetailButton;
UITableViewCellAccessoryNone
UITableViewCellAccessoryDisclosureIndicator
UITableViewCellAccessoryDetailDisclosureButton
UITableViewCellAccessoryCheckmark
UITableViewCellAccessoryDetailButton
  • 选中形式,blue和gray设置后的样式和default一样,不知道什么原因
UITableViewCellSelectionStyleNone,
UITableViewCellSelectionStyleBlue,
UITableViewCellSelectionStyleGray,
UITableViewCellSelectionStyleDefault
cell.selectionStyle = UITableViewCellSelectionStyleNone;

高度

  • 实际开发中,每个cell的高度不尽相同,可以在自定义的模型中,计算好高度属性
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    
}

应用场景的功能

滚动

  • 滚动到指定位置,例如,点击QQ或者微信的输入框,界面自动滚到最后一条消息。滚动有四个位置,但是我尝试了,没有什么区别
[self.tableView scrollToRowAtIndexPath:idxPath //滚动的列和组
atScrollPosition:UITableViewScrollPositionTop //滚动的位置
animated:YES];

UIRefreshControl实现下拉刷新

  • 通过refreshControl,是UITableViewController自带的刷新控件
  • 只要设置了refreshControl,该控件就一直存在
//创建,在viewDidLoad中创建
UIRefreshControl *rc = [UIRefreshControl new];
//指定方法
[rc addTarget:self action:@selector(loadData) forControlEvents:UIControlEventValueChanged];
//菊花颜色
rc.tintColor = [UIColor orangeColor];
//自定义文字
NSDictionary *attrDic = @{
    NSFontAttributeName : [UIFont systemFontOfSize:20],
    NSForegroundColorAttributeName : [UIColor redColor],
    NSBackgroundColorAttributeName : [UIColor blueColor]
};
rc.attributedTitle = [[NSAttributedString alloc] initWithString:@"正在刷新" attributes:attrDic];
self.refreshControl = rc;
//开始,在自定义中,可以重写,进行自定义刷新动画的设置,就需要手动调用
[self.refreshControl beginRefreshing];
//结束
[self.refreshControl endRefreshing];
  • 由于UIRefreshControl在刷新时不会自动调用beginRefreshing,所以要手动调用,并且通过重写beginRefreshingendRefreshing,实现自定义动画效果,把原来的菊花掩盖
  • 自定义UIRefreshControl,下面这个例子,简单的用UIView显示了动画变化,并用KVO的方法调用beginRefreshing
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    if (self.isRefreshing) {
        [UIView animateWithDuration:1 animations:^{
                self.v1.alpha = 0.5;
                self.v2.alpha = 1;
        }];
    }
}
//初始化函数
- (instancetype)init
{
    self = [super init];
    if (self) {
        [self setupUI];
        //kvo检测是否拖动
        [self addObserver:self forKeyPath:@"frame" options:0 context:nil];
    }
    return self;
}

- (void)dealloc
{
    //移除kvo
    [self removeObserver:self forKeyPath:@"frame"];
}
- (void)beginRefreshing {
    [super beginRefreshing];
    NSLog(@"CustomRefreshControl - beginRefreshing");
    [UIView animateWithDuration:1 animations:^{
            self.v1.alpha = 0.5;
            self.v2.alpha = 1;
    }];
}
- (void)endRefreshing {
    [super endRefreshing];
    NSLog(@"CustomRefreshControl - endRefreshing");
    [UIView animateWithDuration:1 animations:^{
            self.v1.alpha = 1;
            self.v2.alpha = 0;
    }];
    
}
- (void)setupUI {
    UIView *v1 = [UIView new];
    v1.frame = CGRectMake(50, 0, self.bounds.size.width, self.bounds.size.height);
    v1.backgroundColor = [UIColor redColor];
    UIView *v2 = [UIView new];
    v2.frame = CGRectMake(50, 0, self.bounds.size.width, self.bounds.size.height);
    v2.backgroundColor = [UIColor blueColor];
    v2.alpha = 0;
    self.tintColor = [UIColor clearColor];
    [self addSubview:v2];
    [self addSubview:v1];
    self.v1 = v1;
    self.v2 = v2;
}

通过headerView实现下拉刷新

  • 但是,用UIRefreshControl,会有一个问题,在实际刷新的时候,刷新的图层会出现在UITableView的上方不是很美观,所以对于不需要headerView的表单中,我选择通过自定义UIView借用headerView来实现下拉刷新
  • RefreshView与自定义UIRefreshControl类似,在beginRefreshingendRefreshing中写出对应的动画,在应该待调用的时候调用,这里就不再重复写了
  • viewDidLoad的基础设置
self.refreshView = [[RefreshView alloc] initWithFrame:CGRectMake(0, 0, 100, 50)];
//获取状态栏高度
CGFloat statusHeight = [UIApplication sharedApplication].windows.firstObject.windowScene.statusBarManager.statusBarFrame.size.height;
//设置tableView的向上偏移量
self.tableView.contentInset = UIEdgeInsetsMake(-50-statusHeight, 0, 0, 0);
self.tableView.tableHeaderView = self.refreshView;
self.refreshFlag = NO;
  • 松手时调用,下拉到一定状态时,进行数据刷新
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
    NSLog(@"%f", scrollView.contentOffset.y);
    if (velocity.y < 0 && self.tableView.contentOffset.y < -self.tableView.tableHeaderView.bounds.size.height) {
        //调用开始刷新
        [self.refreshView beginRefreshing];
        self.refreshFlag = YES;
        //保持界面位置,在刷新头
        self.tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
    }
}
  • 滚动结束时调用,用延时和标志位来模拟数据获取完成
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    CGFloat statusHeight = [UIApplication sharedApplication].windows.firstObject.windowScene.statusBarManager.statusBarFrame.size.height;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        if(self.refreshFlag) {
            [UIView animateWithDuration:0.5 animations:^{
                //数据获取结束,调用结束刷新,并且还原界面位置
                [self.refreshView endRefreshing];
                self.refreshFlag = NO;
                self.tableView.contentInset = UIEdgeInsetsMake(-50-statusHeight, 0, 0, 0);
            }];
            
        }
    });
}

上拉刷新

  • 上拉刷新
  • 往往上拉刷新是不用特别花哨的,用系统自带的即可
//设置上拉刷新视图
self.footerView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleMedium];
self.tableView.tableFooterView = self.footerView;
//开始刷新
[self.footerView startAnimating];
//结束刷新
[self.footerView stopAnimating];

跳转或者执行方法

  • 选中某一行的处理,例如跳转到不同的界面,下面是,根据文本,跳转到界面,将NSString转换成类
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    NSString *targetVC = cell.textLabel.text;
    Class class = NSClassFromString(targetVC);
    UIViewController *vc = [class new];
    [self presentViewController:vc animated:YES completion:nil];
}
  • 这里顺带写一下,将NSString转换为方法名
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSString *targetFunc = cell.textLabel.text;
SEL funcName = NSSelectorFromString(targetFunc);
[self performSelector:funcName];
  • 带参数,如果还要多参数,可以用字典传
//调用
[self performSelector:funcName withObject:@"name" withObject:@18];
//函数
- (void)testViewController:(NSString *)name andAge:(NSNumber *)age {
    NSLog(@"testViewController %@ %d", name, [age intValue]);
}
//cell的内容
cell.textLabel.text = @"testViewController:andAge:";