iOS关于UITableView的用法和问题,都写到这里了!

本文详细介绍了 iOS 开发中 UITableView 的使用方法,包括创建过程、布局设置、单元格内容及高度配置等,并提供了常见错误解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

凡是进行iOS开发的,基本上都会遇到要展示列表,或者即使不是标准列表,但由于数量不固定,也需要如同列表一样从上往下显示、加载的情况。这些,都绕不过对UITableView的使用。

这篇文章就是讲述我对UITableView的认识,帮助和我一样的新人将其更快的理解。

我推荐的创建方式

无论是代码还是Storyboard,你都会发现有两种方式创建与tableview有关的控件。一种是直接创建一个UITableViewController,还有便是在别的ViewController里面创建一个UITableView。

刚开始接触Xcode的时候,我是用Storyboard里面的UITableViewController,觉得上手很快。但是后来发现不太灵活,因为很难在这个里面追加其他的元素。

所以,我推荐大家使用的是:先创建UIViewController,然后在这里面增加一个UITableView,然后再增加其他的控件,可以很从容的布局。

我自己常用的是:UITViewController里面:自定义导航栏+UITableView+自定义工具栏

@interface WebPage()<UITableViewDelegate,UITableViewDataSource>{
    UITableView *tableview;//这个是将要用来创建的列表
  NSMutableArray *webpages;//这个数组是列表内容,通常会是可变的,便于增删改

}
@end

@implementation WebPage

-(void)viewDidLoad{
    [super viewDidLoad];
    webpages = [[NSMutableArray alloc]init];//可变数组要初始化一下,不然不能用,会报错,后面会讲到。
    [self initalView];
}
//初始化界面
-(void)initalView{
    CGRect rx = [ UIScreen mainScreen ].bounds;//获取屏幕尺寸
    self.view.backgroundColor = [UIColor whiteColor];
    
    UIView *Nav = [[UIView alloc]initWithFrame:CGRectMake(0, 0, rx.size.width, 50)];//这个是自定义导航栏,可略过
    Nav.backgroundColor = bluewebpage;
    [self.view addSubview:Nav];
    
    
    
    UIButton *back = [[UIButton alloc]initWithFrame:CGRectMake(10, 10, 30, 30)];
    back.tintColor = [UIColor whiteColor];
    [back setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    back.titleLabel.font = [UIFont systemFontOfSize: 14.0];
    [back setBackgroundImage:[UIImage imageNamed:@"back.png"] forState:UIControlStateNormal];
    [back addTarget:self action:@selector(goback) forControlEvents:UIControlEventTouchUpInside];
    [Nav addSubview:back];
    
    
    
    UIImageView *wishimage =[[UIImageView alloc]initWithFrame:CGRectMake(rx.size.width/2-40-30+15, 10,30, 30)];
    [wishimage setImage:[UIImage imageNamed:@"boximage.png"]];
    [Nav addSubview:wishimage];
    
    
    UILabel *title = [[UILabel alloc]initWithFrame:CGRectMake(rx.size.width/2-40+15, 10, 80, 30)];
    title.text = @"网页";
    title.textAlignment =NSTextAlignmentCenter;
    title.textColor = [UIColor whiteColor];
    title.font = [UIFont systemFontOfSize:18];
    [Nav addSubview:title];
    
    
    UIButton *refresh = [[UIButton alloc]initWithFrame:CGRectMake(rx.size.width-60, 10, 50, 30)];
    refresh.tintColor = [UIColor whiteColor];
    [refresh setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    refresh.titleLabel.font = [UIFont systemFontOfSize: 18.0];
    [refresh setTitle:@"设置" forState:UIControlStateNormal];
    [refresh addTarget:self action:@selector(setmore) forControlEvents:UIControlEventTouchUpInside];
    [Nav addSubview:refresh];
    
    //这个是初始化UITableView
    tableview =[[UITableView alloc]initWithFrame:CGRectMake(0, 50, rx.size.width, rx.size.height-100) style:UITableViewStylePlain];
    tableview.dataSource = self;
    tableview.delegate =self;
    [self.view addSubview:tableview];
    

   //这个是自定义工具栏,可略过
    UIView *toolBarView = [[UIView alloc]initWithFrame:CGRectMake(0, rx.size.height-50, rx.size.width, 50)];
    toolBarView.backgroundColor = [UIColor bluecolor];

    [self.view addSubview:toolBarView];
    
    UIButton *addwebpage = [[UIButton alloc]initWithFrame:CGRectMake(10, 10, 30, 30)];
    addwebpage.tintColor = [UIColor whiteColor];
    [addwebpage setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    addwebpage.titleLabel.font = [UIFont systemFontOfSize: 14.0];
    [addwebpage setTitle:@"添加" forState:UIControlStateNormal];
    

    [addwebpage addTarget:self action:@selector(newpage) forControlEvents:UIControlEventTouchUpInside];
    [toolBarView addSubview:addwebpage];
    
    
    UIButton *sharebtn = [[UIButton alloc]initWithFrame:CGRectMake(rx.size.width/2-15, 10, 30, 30)];
    sharebtn.tintColor = [UIColor whiteColor];
    [sharebtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    sharebtn.titleLabel.font = [UIFont systemFontOfSize: 14.0];
    [sharebtn setTitle:@"分享" forState:UIControlStateNormal];
    [sharebtn addTarget:self action:@selector(share) forControlEvents:UIControlEventTouchUpInside];
    [toolBarView addSubview:sharebtn];
    
    
    
    UIButton *previewpage = [[UIButton alloc]initWithFrame:CGRectMake(rx.size.width-50, 10, 30, 30)];
    previewpage.tintColor = [UIColor whiteColor];
    [previewpage setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    previewpage.titleLabel.font = [UIFont systemFontOfSize: 14.0];
    [previewpage setTitle:@"预览" forState:UIControlStateNormal];
    [previewpage addTarget:self action:@selector(preview) forControlEvents:UIControlEventTouchUpInside];
    [toolBarView addSubview:previewpage];

    
}

关于创建流程的简要说明

1.首先,肯定是要创建内容数组和tableview了。

2.然后要对tableview有个基本设置,包括下面写到的:

1)delegate和datasource:不设置会显示不出tableview,但也不会崩溃

2)整体布局:不设置或设置的不对,会崩溃

3)cell的内容和高度:不设置或设置的不对,会崩溃

其中,整体布局与cell的内容和高度是有相关性的,而且往往都会与内容数组有直接关系,如果对不上,就可能崩溃。

如果内容数组的内容是异步加载,或动态更新的话,那么还有两步:

3.更新数组,无论是从本地数据中还是网络中

4.[tableview reloadData];//这个tableview是你自己创建的那个。


关于delegate和datasource

在上文中可以看到:

tableview.dataSource = self;
    tableview.delegate =self;
这个是非常重要的,这个决定了tableview是否能够被使用,以及能否把数据加载到tableview里面去。

没太多可说的,加上这两行代码就好了。

说明:直接创建UITableViewController,就不用写这两行代码了。如果是在storyboard里面创建的,可以救灾storyboard里面关联。


整体布局

这个不写的话,会直接崩溃

-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
    return 2;
}



-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if (section == 0) {
        return 1;
    }else{
    return webpages.count;
    }
}





关于cell内容及高度的

TableView里面的每一行格子被称为cell,这个不难理解。必须设置内容(可以为空)和高度,否则崩溃。

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSUInteger section = [indexPath section];
    if (section==0) {
        static NSString *CellIdentifier = @"WebCoverCell";
        WebCoverCell *cell= [tableview dequeueReusableCellWithIdentifier:CellIdentifier];
        
        if (cell == nil) {
            cell = [[WebCoverCell alloc] initWithReuseIdentifier:CellIdentifier];
        }
       //这里写内容
        
        return cell;
    }
    else{
   
    WebPageCell *cell= [tableview dequeueReusableCellWithIdentifier:CellIdentifier];
    
    if (cell == nil) {
        cell = [[WebPageCell alloc] initWithReuseIdentifier:CellIdentifier];
    }
       //这里写内容,但是最好是调用你在cell布局里面写好的控件;也能添加新的控件,但最好不要这样做,因为这样的话,在列表上下滚动的时候,这个cell里面就会不断创建你添加的这个新控件。
如:cell.webpage_label.text=@"haha";cell.webpage_image.image =...;
cell.background_image=...;

    return cell;
    }
}

关于cell自己的布局,用默认的基本不够用,所以一般是会自定义的

//
//  UITableViewCell+WebPageCell.h
//  wenyi
//
//  Created by li xinglin on 16/3/5.
//  Copyright © 2016年 nashihuakai team. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface WebPageCell:UITableViewCell
@property (nonatomic,retain)  UILabel *webpage_label;
@property (retain, nonatomic)  UIImageView *webpage_image;
@property (retain, nonatomic)  UIImageView *background_image;

-(id)initWithReuseIdentifier:(NSString*)reuseIdentifier;
@end


//
//  UITableViewCell+WebPageCell.m
//  wenyi
//
//  Created by li xinglin on 16/3/5.
//  Copyright © 2016年 nashihuakai team. All rights reserved.
//

#import "UITableViewCell+WebPageCell.h"

@implementation WebPageCell
-(id)initWithReuseIdentifier:(NSString*)reuseIdentifier{
    
    self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
    
    if (self) {
        
        [self initLayuot];
        
    }
   
    
    return self;
    
}

//初始化控件

-(void)initLayuot{
    
    CGRect rx = [ UIScreen mainScreen ].bounds;//获取屏幕尺寸
    
    int cellheight = 0;
    self.background_image = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, rx.size.width, 60)];
    [self addSubview:self.background_image];
    
    
    
    self.webpage_image = [[UIImageView alloc] initWithFrame:CGRectMake(10, 5, 70, 70)];
    self.webpage_image.contentMode = UIViewContentModeScaleAspectFill;//图片不会变形!!!!!!
    self.webpage_image.clipsToBounds  = YES;//保证多余的部分不会显示!!!!!
    self.webpage_image.backgroundColor = [UIColor groupTableViewBackgroundColor];
    
    [self addSubview:self.webpage_image];
    
    self.webpage_label = [[UILabel alloc] initWithFrame:CGRectMake(10, 5, rx.size.width-20, 70)];
    //self.webpage_label.font = [UIFont fontWithName:fontstyle_yinxiang size:16];
    //self.webpage_label.textAlignment = NSTextAlignmentLeft;
    //self.webpage_label.lineBreakMode = NSLineBreakByCharWrapping;
    
    self.webpage_label.numberOfLines = 3; // 最关键的一句
    [self addSubview:self.webpage_label];
    
    cellheight +=80;
    //设置当前cell高度
    
    CGRect frame = [self frame];
    
    frame.size.height = cellheight;
    
    self.frame = frame;
}



- (void)setSelected:(BOOL)selected animated:(BOOL)animated

{
    
    // [super setSelected:selected animated:animated]; 这样就没有点击时的效果了
    
    
    
}
-(void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated

{
    
}
@end




设置cell的高度

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    //  NSUInteger section = [indexPath section];
    
    if (indexPath.section==0) {
        return SCREENWIDTH*5/8+40+40;
    }
    else{
    return 80;
        /*如果高度不固定的话
        WebPageCell *cell =(WebPageCell*)[self tableView:tableview cellForRowAtIndexPath:indexPath];
        return cell.frame.size.height;
         */
    }
}



关于更多布局的

//直接写header的

//-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
//{
//
//    NSString *groupname = [self.headers objectAtIndex:section];
//    return groupname;
//}

//section头部间距
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return 10;//section头部高度
}
//section头部视图
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    UIView *view=[[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 10)];
    view.backgroundColor = [UIColor clearColor];
    return view;
}
//section底部间距
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
    return 1;
}
//section底部视图
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
    UIView *view=[[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 10)];
    view.backgroundColor = [UIColor clearColor];
    return view;
}



关于TableView的操作的

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    NSInteger section = [indexPath section];
    if (section==0) {
//个别情况下,需要调用一下主线程,我也没搞懂
        dispatch_async(dispatch_get_main_queue(), ^{
        SetWeb *setwebcontrollor =[[SetWeb alloc]init];
        setwebcontrollor.isEdit =YES;
        setwebcontrollor.web = self.web;
        [self presentViewController:setwebcontrollor animated:YES completion:NULL];
        });
    }
    else{
        
        NSDictionary *webpage = [self.webpages objectAtIndex:indexPath.row];
        NSString *content = [webpage objectForKey:@"web_page_content"];
        NSString *videourl = [webpage objectForKey:@"web_page_videourl"];
        
            dispatch_async(dispatch_get_main_queue(), ^{
            WebPageWord *webpagesetcontrollor =[[WebPageWord alloc]init];
            webpagesetcontrollor.isEdit =YES;
            webpagesetcontrollor.web = self.web;
            webpagesetcontrollor.webpage = [self.webpages objectAtIndex:indexPath.row];
            [self presentViewController:webpagesetcontrollor animated:YES completion:NULL];
                });
        
        
        
    }
    
    
    
}


- (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath{
    
    
  //  NSDictionary *webpage = [self.webpages objectAtIndex:indexPath.row];
   // int wishid = [[webpage objectForKey:@"wishid"] intValue];
    //int status = [[webpage objectForKey:@"status"] intValue];
    
    
    //设置删除按钮
    UITableViewRowAction *deleteRowAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDestructive title:@"删除" handler:^(UITableViewRowAction *action,NSIndexPath *indexPath) {
        
        
        UIAlertController * alertController = [UIAlertController alertControllerWithTitle: nil
                                                                                  message: @"确定要删除吗?"
                                                                           preferredStyle:UIAlertControllerStyleAlert];
        [alertController addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
            
            
        }]];
        [alertController addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
            
            
            [self deleteWeb:indexPath];
            
            /*
             [self.webpages removeObjectAtIndex:indexpath.row];
             [tableview deleteRowsAtIndexPaths:@[indexpath] withRowAnimation:UITableViewRowAnimationAutomatic];
             
*/
            
            
        }]];
        
        [self presentViewController:alertController animated:YES completion:nil];
        
        
        
        
        
        //在数据库中删除
        
        
        
        
        
    }];
    
    //设置收藏按钮
    UITableViewRowAction *collectRowAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:@"下移" handler:^(UITableViewRowAction *action,NSIndexPath *indexPath) {
        if (indexPath.row == self.webpages.count-1) {
            //
        }else{
        [self moveWeb:indexPath direction:0];
        }
        /*
         [self.webpages exchangeObjectAtIndex:(int)indexpath.row withObjectAtIndex:movetorow];
         NSIndexPath *newindexpath = [NSIndexPath indexPathForRow:movetorow inSection:indexpath.section];
         [tableview moveRowAtIndexPath:indexpath toIndexPath:newindexpath];
         */
        
        
        
    }];
    
        collectRowAction.backgroundColor = [UIColor orangeColor];
    
    
     //设置置顶按钮
     UITableViewRowAction *topRowAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:@"上移"handler:^(UITableViewRowAction *action,NSIndexPath *indexPath) {
         if (indexPath.row == 0) {
             //
         }else{
     
         [self moveWeb:indexPath direction:1];
         }
         /*
          [self.webpages exchangeObjectAtIndex:(int)indexpath.row withObjectAtIndex:movetorow];
          NSIndexPath *newindexpath = [NSIndexPath indexPathForRow:movetorow inSection:indexpath.section];
          [tableview moveRowAtIndexPath:indexpath toIndexPath:newindexpath];
          */
     
     }];
     
     //collectRowAction.backgroundEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
     
     topRowAction.backgroundColor = greenstory;
    
    //设置插入按钮
    UITableViewRowAction *insertRowAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:@"插入"handler:^(UITableViewRowAction *action,NSIndexPath *indexPath) {
        
            
            insertnumber = (int)indexPath.row;
            [self popView];
        
        
        
    }];
    
    //collectRowAction.backgroundEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
    
    insertRowAction.backgroundColor = bluewebpage;
    
    if (indexPath.section == 1) {
        if (indexPath.row ==0) {
            if (self.webpages.count==1) {
                return  @[deleteRowAction,insertRowAction];

            }else{
            return  @[deleteRowAction,collectRowAction,insertRowAction];
            }

        }else if(indexPath.row ==self.webpages.count-1){
            return  @[deleteRowAction,topRowAction,insertRowAction];

        }else{
            return  @[deleteRowAction,collectRowAction,topRowAction,insertRowAction];

        }
    }else{
    
    return  nil;
    }
}




容易出错的情况

1.没有绑定delegate和datasource:现象是tableview为空或没反应;

2.收到错误参数:考虑内容数组没有初始化;数组与布局不匹配;

3.操作时发生崩溃

首先需要注意的是,tableview中的增加、删减操作,往往要与内容数组同步进行。否则当二者不统一的时候,容易发生崩溃,尤其是列表在上下滑动的时候。

我发生的一个例子:

在使用下拉刷新的时候,我们往往要先设置原来的内容数组为空,然后把新获取到的数组添加进去,再reload这个tableview。看起来很简单,但我去弄错过很多次。

事实上,严格的顺序是这样:1)先获取,无论是从本地还是网络,2)获取成功后,清空原来的数组,添加新数组;3)[tableview reloadData];

我有时忘记了,会在获取之前就清空数组,结果在下拉列表回弹的时候,由于要加载数组,致使程序崩溃。






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值