【IOS初学者】UITableView与自定义UITableViewCell

在IOS开发中用的最为普遍的组件,莫过于UITableView,今天在这篇文章中会详细介绍一下UITableView和UITableViewCell。javascript


什么是UITableView

UITableView有两种形式,一种是分组的,一种是不分组的,下面来看一下样式:java

  • 分组样式(UITableViewStyleGrouped)

  • 不分组样式(UITableViewStylePlain)

UITableView中每行数据都是一个UITableViewCell,在这个控件中为了显示更多的信息,iOS已经在其内部设置好了多个子控件以供开发者使用。
查看源码可知:缓存

typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
    UITableViewCellStyleDefault,    // 左侧显示textLabel(不显示detailTextLabel),imageView可选(显示在最左边)
    UITableViewCellStyleValue1,        // 左侧显示textLabel、右侧显示detailTextLabel(默认蓝色),imageView可选(显示在最左边)
    UITableViewCellStyleValue2,        // 左侧依次显示textLabel(默认蓝色)和detailTextLabel,imageView可选(显示在最左边)
    UITableViewCellStyleSubtitle    // 左上方显示textLabel,左下方显示detailTextLabel(默认灰色),imageView可选(显示在最左边)
};复制代码

固然,这些子控件并不必定要所有使用,具体操做时能够经过UITableViewCellStyle进行设置。性能优化

#如何实现UITableView
在实现UITableView以前,咱们先创建一个数据模型,让UITableView来进行展现:性能

@interface Person : NSObject


@property (nonatomic,copy) NSString *name;
@property (nonatomic,copy) NSString *sex;
@property (nonatomic,copy) NSString *age;
-(Person *)initWithName:(NSString *)name andSex:(NSString *)sex andAge:(NSString *)age;
@end复制代码

实现:优化

-(Person *)initWithName:(NSString *)name andSex:(NSString *)sex andAge:(NSString *)age{
    if(self=[super init]){
        self.name=name;
        self.age=age;
        self.sex=sex;
    }
    return self;
}复制代码

而后在ViewController中添加实现,根据上文中提到过的两种方式,咱们进行分别的实现。ui

UITableViewStylePlain

实现一个UITableView,好比要有一个数据源,若是须要有交互(点击)那么还须要一个代理,即UITableViewDataSource和UITableViewDelegate。atom

那咱们能够都在当前的ViewController中实现:spa

UITableViewDataSource

对于数据源咱们能够有以下实现:代理

//有几个群组
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
    return 1;
}
//一个群组有几个item(cell)
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return _persons.count;
}
//根据数据源展现界面实现
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
      Person *person=_persons[indexPath.row];
    UITableViewCell *cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
    cell.textLabel.text=[person name];
    cell.detailTextLabel.text=person.sex;
    return cell;
}复制代码

UITableViewDelegate

点击实现,咱们能够实现以下的方法:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
     Person *person=_persons[indexPath.row];
    UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"title" message:person.age delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"ok", nil];
    [alert show];
}复制代码

初始化UITableView

而后在初始化UITableView便可:

- (void)viewDidLoad {
    [super viewDidLoad];
    [self initData];
    _tableView=[[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStylePlain];
    _tableView.dataSource=self;
    _tableView.delegate = self;
    [self.view addSubview:_tableView];

}
-(void)initData{
    _persons = [[NSMutableArray alloc]init];
      _mans = [[NSMutableArray alloc]init];
      _womans = [[NSMutableArray alloc]init];
     Person *person1 = [[Person alloc]initWithName:@"jack" andSex:@"man" andAge:@"15"];
     Person *person2 = [[Person alloc]initWithName:@"jim" andSex:@"man" andAge:@"15"];
     Person *person3 = [[Person alloc]initWithName:@"jj" andSex:@"man" andAge:@"15"];
     Person *person4 = [[Person alloc]initWithName:@"jk" andSex:@"man" andAge:@"15"];
     Person *person5 = [[Person alloc]initWithName:@"jff" andSex:@"man" andAge:@"15"];
     Person *person6 = [[Person alloc]initWithName:@"tom" andSex:@"man" andAge:@"15"];
    NSArray *arryman = [NSArray arrayWithObjects:person1,person2,person3,person4,person5,person6,nil];
    [self.mans addObjectsFromArray:arryman];

    Person *person11 = [[Person alloc]initWithName:@"lily" andSex:@"women" andAge:@"15"];
    Person *person21 = [[Person alloc]initWithName:@"lucy" andSex:@"women" andAge:@"15"];
    Person *person31 = [[Person alloc]initWithName:@"ll" andSex:@"women" andAge:@"15"];
    Person *person41 = [[Person alloc]initWithName:@"lk" andSex:@"women" andAge:@"15"];
    Person *person51 = [[Person alloc]initWithName:@"lf" andSex:@"women" andAge:@"15"];
    Person *person61 = [[Person alloc]initWithName:@"nancy" andSex:@"women" andAge:@"15"];
    NSArray *arrywoman = [NSArray arrayWithObjects:person11,person21,person31,person41,person51,person61,nil];
    [self.womans addObjectsFromArray:arrywoman];

    [_persons addObjectsFromArray:_mans];
    [_persons addObjectsFromArray:_womans];

}复制代码

UITableViewStyleGrouped

根据上面的例子咱们知道,仍是须要实现UITableViewDataSource和UITableViewDelegate。

UITableViewDataSource

在这种形式的UITableViewDataSource,咱们须要多实现一些东西:

-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
    return 2;//假设咱们有两个群组
}
//根据section来区分是哪一个群组
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    if (section == 0) {
        return _mans.count;
    }
    else  {
        return _womans.count;
    }

}
//实现展现界面的时候也要区分群组
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    Person *person;
    if(indexPath.section == 0){
        person = _mans[indexPath.row];
    }else{
        person = _womans[indexPath.row];
    }

    UITableViewCell *cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
    cell.textLabel.text=[person name];
    cell.detailTextLabel.text=person.sex;
    return cell;
}
// 返回每组头标题名称
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{

    if (section == 0) {
        return @"man";
    }else{
        return @"woman";
    }

}

// 返回每组尾部说明
-(NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section{
    if (section == 0) {
        return @"man footer";
    }else{
        return @"woman footer";
    }

}复制代码

UITableViewDelegate

在UITableViewDelegate的实现中也要区分群组:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    Person *person;
    if(indexPath.section == 0){
        person = _mans[indexPath.row];
    }else{
        person = _womans[indexPath.row];
    }
    UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"title" message:person.age delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"ok", nil];
    [alert show];
}复制代码

初始化UITableView

这里跟上面基本同样,惟一的区别就是设置类型为UITableViewStyleGrouped

_tableView=[[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStyleGrouped];复制代码

更多功能

设置行高

在UITableViewDelegate中还有一些特殊的功能,经过一些方法来实现:

#pragma mark 设置分组标题内容高度
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
    if(section==0){
        return 50;
    }
    return 40;
}

#pragma mark 设置每行高度(每行高度能够不同)
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    return 45;
}

#pragma mark 设置尾部说明内容高度
-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{
    return 40;
}复制代码

生成索引

在UITableViewDataSource中还有一些特殊的功能,经过一些方法来实现:

#pragma mark 返回每组标题索引
-(NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView{
    NSLog(@"生成组索引");
    NSMutableArray *indexs=[[NSMutableArray alloc]init];
        [indexs addObject:@"man"];
      [indexs addObject:@"woman"];
    return indexs;
}复制代码

性能优化

UITableView中的单元格cell是在显示到用户可视区域后建立的,那么若是用户往下滚动就会继续建立显示在屏幕上的单元格,若是用户向上滚动返回到查看过的内容时一样会从新建立以前已经建立过的单元格。如此一来即便UITableView的内容不是太多,若是用户反复的上下滚动,内存也会瞬间飙升,更况且不少时候UITableView的内容是不少的(例如微博展现列表,基本向下滚动是没有底限的)。
作过Android的同窗应该知道,在ListView中有一种机制,就是复用view来作优化,IOS的UITableView中其实已经自我实现了这种机制,也就是将当前没有显示的Cell从新显示在将要显示的Cell的位置而后更新其内容。
在UITableView内部有一个缓存池,初始化时使用initWithStyle:(UITableViewCellStyle) reuseIdentifier:(NSString *)方法指定一个可重用标识,就能够将这个cell放到缓存池。而后在使用时使用指定的标识去缓存池中取得对应的cell而后修改cell内容便可。

#pragma mark返回每行的单元格
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    Person *person;
    if(indexPath.section == 0){
        person = _mans[indexPath.row];
    }else{
        person = _womans[indexPath.row];
    }
    //因为此方法调用十分频繁,cell的标示声明成静态变量有利于性能优化
    static NSString *cellIdentifier=@"UITableViewCellIdentifierKey1";
    //首先根据标识去缓存池取
    UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if(!cell){
        cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier];
    }

    cell.textLabel.text=[person name];
    cell.detailTextLabel.text=person.sex;
    return cell;
}复制代码

UITableViewCell

原生的UITableViewCell

UITableViewCell是构建一个UITableView的基础,在UITableViewCell内部有一个UIView控件做为其余内容的容器,它上面有一个UIImageView和两个UILabel,经过UITableViewCellStyle属性能够对其样式进行控制。

typedef NS_ENUM(NSInteger, UITableViewCellAccessoryType) {
    UITableViewCellAccessoryNone,                   // 不显示任何图标
    UITableViewCellAccessoryDisclosureIndicator,    // 跳转指示图标
    UITableViewCellAccessoryDetailDisclosureButton, // 内容详情图标和跳转指示图标
    UITableViewCellAccessoryCheckmark,              // 勾选图标
    UITableViewCellAccessoryDetailButton NS_ENUM_AVAILABLE_IOS(7_0) // 内容详情图标
};复制代码

添加自定义组件

若是上述的属性我都不想用,好比我想用一个UISwitch控件,应该如何进行设置呢?
继续修改一下-(UITableViewCell )tableView:(UITableView )tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    Person *person;
    if(indexPath.section == 0){
        person = _mans[indexPath.row];
    }else{
        person = _womans[indexPath.row];
    }
    //因为此方法调用十分频繁,cell的标示声明成静态变量有利于性能优化
    static NSString *cellIdentifier=@"UITableViewCellIdentifierKey1";
    static NSString *cellIdentifierForFirstRow=@"UITableViewCellIdentifierKeyWithSwitch";
    //首先根据标识去缓存池取
    UITableViewCell *cell;
    if (indexPath.row==0) {
        cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifierForFirstRow];
    }else{
        cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    }
    if(!cell){
        if (indexPath.row==0) {
            cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifierForFirstRow];
            UISwitch *sw=[[UISwitch alloc]init];
            [sw addTarget:self action:@selector(switchValueChange:) forControlEvents:UIControlEventValueChanged];
            cell.accessoryView=sw;

        }else{
            cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier];
            cell.accessoryType=UITableViewCellAccessoryDetailButton;
        }
    }

    if(indexPath.row==0){
        ((UISwitch *)cell.accessoryView).tag=indexPath.section;
    }

    cell.textLabel.text=[person name];
    cell.detailTextLabel.text=person.sex;
    return cell;
}
#pragma mark 切换开关转化事件
-(void)switchValueChange:(UISwitch *)sw{
    NSLog(@"section:%li,switch:%i",(long)sw.tag, sw.on);
}复制代码

代码表示咱们在第一行添加了一个开关的控件。
效果如图:

自定义UITableViewCell

假如系统提供的UITableViewCell知足不了咱们的须要,咱们能够进行自定义,新建一个CustomCellTableViewCell继承UITableViewCell

#import <UIKit/UIKit.h>
#import "Person.h"
@interface CustomCellTableViewCell : UITableViewCell
@property (nonatomic,strong) Person *person;
@property (assign,nonatomic) CGFloat height;
@end复制代码

实现:

@interface CustomCellTableViewCell(){


    UILabel *_text1;
     UILabel *_text2;
     UILabel *_text3;
}

@end
@implementation CustomCellTableViewCell

- (void)awakeFromNib {
    // Initialization code
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
}
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        [self initSubView];
    }
    return self;
}
#pragma mark 初始化视图
-(void)initSubView{
    _text1=[[UILabel alloc]init];
    _text1.textColor=[UIColor redColor];
    [_text1 setFrame:CGRectMake(0, 0, 40, 20)];
     [self.contentView addSubview:_text1];
    _text2=[[UILabel alloc]init];
    _text2.textColor=[UIColor yellowColor];
    [_text2 setFrame:CGRectMake(40, 0, 40, 20)];

    [self.contentView addSubview:_text2];
    _text3=[[UILabel alloc]init];
    _text3.textColor=[UIColor blueColor];
    [_text3 setFrame:CGRectMake(80, 0, 40, 20)];

    [self.contentView addSubview:_text3];
}

#pragma mark 设置
-(void)setPerson:(Person *)person{
    [_text1 setText:person.name];
 [_text2 setText:person.sex];
     [_text3 setText:person.age];
}
@end复制代码

而后修改一下使用的ViewController

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    static NSString *cellIdentifier=@"UITableViewCellIdentifierKey1";
    CustomCellTableViewCell *cell;
    cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if(!cell){
        cell=[[CustomCellTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
    }
        Person *person;
        if(indexPath.section == 0){
            person = _mans[indexPath.row];
        }else{
            person = _womans[indexPath.row];
        }
    cell.person=person;
    return cell;
}复制代码

效果以下图所示:

UITableViewController

不少时候一个UIViewController中只有一个UITableView,所以苹果官方为了方便你们开发直接提供了一个UITableViewController,这个控制器 UITableViewController实现了UITableView数据源和代理协议,内部定义了一个tableView属性供外部访问,同时自动铺满整个屏幕、自动伸缩以方便咱们的开发。
实现起来跟前面提到的都同样,因此,这里再也不赘述。

总结

UITableView确实给咱们提供了一些很强大的功能和展现效果,用好用对UITableView对于IOS程序开发是很是有必要的。

相关文章
相关标签/搜索