iOS开发中经常会用到UITableView,我们平时使用的软件中到处都可以看到它,比如微信、QQ、微博等软件基本上随处都是UITableView。最主要到还有iOS设置。
UITableView有两种Style:UITableViewStylePlain和UITableViewStyleGrouped。从名字上可以看出:一个是普通样式的,另一个是分组样式的。具体上怎样,可以看一下下面的图片。
普通样式(不分组) 分组样式:
UITableView只有行没有列,每一行都是一个UITableViewCell,如果我们查看UITableViewCell的声明文件可以发现在内部有一个UIView控件(contentView,作为其他元素的父控件)、两个UILable控件(textLabel detailTextLabel)、一个UIImage控件(imageView),分别用于容器、显示内容、详情和图片。这些控件并不一定要全部显示,可以根据需要设置。
typedef NS_ENUM(NSInteger, UITableViewCellStyle) { UITableViewCellStyleDefault, // Simple cell with text label and optional image view (behavior of UITableViewCell in iPhoneOS 2.x) UITableViewCellStyleValue1, // Left aligned label on left and right aligned label on right with blue text (Used in Settings) UITableViewCellStyleValue2, // Right aligned label on left with blue text and left aligned label on right (Used in Phone/Contacts) UITableViewCellStyleSubtitle // Left aligned label on top and left aligned label on bottom with gray text (Used in iPod). };这是UITalbeViewCell的四种style。
UITableView需要一个数据源(dataSource)来显示数据,UITableView会向数据源查询一共有多少行数据以及每一行显示什么数据等。没有设置数据源的UITableView只是个空壳。凡是遵守UITableViewDataSource协议的OC对象,都可以是UITableView的数据源。
首先将UITableView对数据源和View controller相连。如图所示:
并且让这个ViewController这个类实现UITableViewDataSource协议。
#import <UIKit/UIKit.h> @interface ViewController : UIViewController <UITableViewDataSource,UITableViewDelegate> @end
先看一下UITableViewDataSource协议:
@protocol UITableViewDataSource<NSObject> @required //必须要实现的 第section分区一共有多少行 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section; //创建第section分区第row行的UITableViewCell对象(indexPath包含了section和row) - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath; @optional //可选择实现的 // 一共有多少个分区 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView; //第section分区的头部标题 - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section; //第section分区的底部标题 - (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section; //某一行是否可以编辑(删除) - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath; //某一行是否可以移动来进行重新排序 - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath; UITableView右边的索引栏的内容 - (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView;
这些只是UITableView的显示上面的设置,如果要做一些操作仅这些是不够的。。。
通常都要为UITableView设置代理对象(delegate),以便在UITableView触发一下事件时做出相应的处理,比如选中了某一行。凡是遵守了UITableViewDelegate协议的OC对象,都可以是UITableView的代理对象。一般会让控制器充当UITableView的dataSource和delegate。
同样需要将UITableView的delegate与UIViewController关联起来。
看一些UITableViewDelegate协议的一些常用方法。
@protocol UITableViewDelegate<NSObject, UIScrollViewDelegate> @optional //选中了UITableView的某一行 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath //某一行的高度 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath //第section分区头部的高度 - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section //第section分区尾部的高度 - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section //第section分区头部显示的视图 - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section //第section分区尾部显示的视图 - (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section //设置每一行的等级缩进(数字越小,等级越高) - (NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath
先看一下最基本的UITableView。
#pragma mark 这一组里面有多少行 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ return 9; } #pragma mark 返回第indexPath这行对应的内容 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { /* 四种style,分别是 Default : 不显示detailTextLabel Value1 : 在右边显示detailTextLabel Value2 : 不显示图片,显示detailTextLabel Subtitle : 在底部显示detailTextLabel */ UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:nil]; cell.textLabel.text = [NSString stringWithFormat:@"金克斯-%ld", indexPath.row]; return cell; }
通过设置:UITableViewCell的detailTextLabel和imgName的两个属性。
#pragma mark 返回第indexPath这行对应的内容 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:nil]; cell.textLabel.text = [NSString stringWithFormat:@"金克斯-%ld", indexPath.row]; // 设置详情文字 cell.detailTextLabel.text = [NSString stringWithFormat:@"英雄-%ld非常好玩!!!!!", indexPath.row]; // 设置图片 NSString *imgName = @"jinkesi.png";//[NSString stringWithFormat:@"00%d.png", indexPath.row + 1]; cell.imageView.image = [UIImage imageNamed:imgName]; return cell; }
#import "ViewController.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; _rowLanguage = [[NSMutableArray alloc] initWithObjects:NSLocalizedString(@"str_language_itemTitle_zh", nil) ,NSLocalizedString(@"str_language_itemTitle_en", nil) ,NSLocalizedString(@"str_language_itemTitle_ar", nil) ,NSLocalizedString(@"str_language_itemTitle_de", nil) ,NSLocalizedString(@"str_language_itemTitle_es", nil) ,NSLocalizedString(@"str_language_itemTitle_fa", nil) ,NSLocalizedString(@"str_language_itemTitle_fr", nil) ,NSLocalizedString(@"str_language_itemTitle_it", nil) ,NSLocalizedString(@"str_language_itemTitle_pt", nil) ,NSLocalizedString(@"str_language_itemTitle_ru", nil) ,NSLocalizedString(@"str_language_itemTitle_th", nil) ,nil]; } - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ return 1; } #pragma mark 这一组里面有多少行 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ return 9; } #pragma mark 返回第indexPath这行对应的内容 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:nil]; cell.textLabel.text = [_rowLanguage objectAtIndex:indexPath.row]; return cell; }
将数据使用模型封装数据。建立模型类Heros
Heros.hs文件
#import <Foundation/Foundation.h> @interface Heros : NSObject @property (nonatomic, copy) NSString *name; //名字 @property (nonatomic, copy) NSString *icon;//图片 @property (nonatomic, copy) NSString *desc;//描述 +(Heros *)initWithName:(NSString *)name andicon:(NSString *)icon anddees:(NSString *)desc; @endHeros.m文件
#import "Heros.h" @implementation Heros //初始化方法 +(Heros *)initWithName:(NSString *)name andicon:(NSString *)icon anddees:(NSString *)desc{ Heros *hero = [[Heros alloc]init]; hero.name = name; hero.icon = icon; hero.desc = desc; return hero; } @endViewController.m文件
#import "ViewController.h" #import "Heros.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; Heros *heros1 = [Heros initWithName:@"薇恩" andicon:@"vn.png" anddees:@"让我们来猎杀那些陷入黑暗中的人吧。"]; Heros *heros2 = [Heros initWithName:@"男枪" andicon:@"nanqian.png" anddees:@"我与死亡同行。"]; Heros *heros3 = [Heros initWithName:@"赏金" andicon:@"shangjin.png" anddees:@"好运,不会眷顾傻瓜。"]; Heros *heros4 = [Heros initWithName:@"奎因" andicon:@"kuiyin.png" anddees:@"正义,展翅翱翔。"]; Heros *heros5 = [Heros initWithName:@"金克斯" andicon:@"jinkesi.png" anddees:@"规则,就是用来打破的。"]; Heros *heros6 = [Heros initWithName:@"奥巴马" andicon:@"luxian.png" anddees:@"人终有一死,可有些人需要一点小小的帮助。"]; Heros *heros7 = [Heros initWithName:@"希维尔" andicon:@"xiweier.png" anddees:@"你有麻烦了,我有钱赚。"]; Heros *heros8 = [Heros initWithName:@"伊泽瑞尔" andicon:@"yizeruier.png" anddees:@"是时候表演真正的技术啦。"]; Heros *heros9 = [Heros initWithName:@"复仇之矛" andicon:@"fuchouzhi.png" anddees:@"我们的誓约,以血为契。"]; _arrayHeros = [[NSMutableArray alloc]initWithObjects:heros1,heros2,heros3,heros4,heros5,heros6,heros7,heros8,heros9, nil]; } - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ return 1; } #pragma mark 这一组里面有多少行 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ return _arrayHeros.count; } #pragma mark 返回第indexPath这行对应的内容 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:nil]; Heros *he = [_arrayHeros objectAtIndex:indexPath.row]; cell.textLabel.text = he.name; //设置名字 cell.detailTextLabel.text = he.desc; //设置描述 cell.imageView.image =[UIImage imageNamed:he.icon]; //设置图片 return cell; } #pragma mark - 代理方法 #pragma mark 返回indexPath这行cell的高度 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return 45; } #pragma mark 选中一行响应事件 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { } @end
UITableView的每一行都是一个UITableViewCell,通过dataSource的tableView:cellForRowAtIndexPath:方法来初始化每一行
UITableViewCell是UIView的子类,内部有个默认的子视图:contentView。contentView是UITableViewCell所显示内容的父视图,并负责显示一些辅助指示视图。辅助指示视图的作用是显示一个表示动作的图标,可以通过设置UITableViewCell的accessoryType来显示,默认是UITableViewCellAccessoryNone。
typedef NS_ENUM(NSInteger, UITableViewCellAccessoryType) { UITableViewCellAccessoryNone, // don't show any accessory view UITableViewCellAccessoryDisclosureIndicator, // regular chevron. doesn't track UITableViewCellAccessoryDetailDisclosureButton __TVOS_PROHIBITED, // info button w/ chevron. tracks UITableViewCellAccessoryCheckmark, // checkmark. doesn't track UITableViewCellAccessoryDetailButton NS_ENUM_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED // info button. tracks };
查看对应显示。
#pragma mark 返回第indexPath这行对应的内容 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:nil]; Heros *he = [_arrayHeros objectAtIndex:indexPath.row]; cell.textLabel.text = he.name; //设置名字 cell.detailTextLabel.text = he.desc; //设置描述 cell.imageView.image =[UIImage imageNamed:he.icon]; //设置图片 if(indexPath.row == 0 ||indexPath.row ==1) cell.accessoryType = UITableViewCellAccessoryNone; else if (indexPath.row == 2 || indexPath.row == 3) cell.accessoryType = UITableViewCellAccessoryCheckmark; else if (indexPath.row == 4 || indexPath.row == 5) cell.accessoryType = UITableViewCellAccessoryDetailButton; else if(indexPath.row == 6 || indexPath.row == 7) cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; else cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;//有俩图标。 return cell; }
#pragma mark 返回第indexPath这行对应的内容 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:nil]; Heros *he = [_arrayHeros objectAtIndex:indexPath.row]; cell.textLabel.text = he.name; //设置名字 cell.detailTextLabel.text = he.desc; //设置描述 cell.imageView.image =[UIImage imageNamed:he.icon]; //设置图片 if(indexPath.row == 0 ||indexPath.row ==1){ cell.accessoryType = UITableViewCellAccessoryNone; cell.backgroundColor = [UIColor blueColor]; } else if (indexPath.row == 2 || indexPath.row == 3){ cell.accessoryType = UITableViewCellAccessoryCheckmark; cell.backgroundColor = [UIColor yellowColor]; } else if (indexPath.row == 4 || indexPath.row == 5){ cell.accessoryType = UITableViewCellAccessoryDetailButton; cell.backgroundColor = [UIColor redColor]; } else if(indexPath.row == 6 || indexPath.row == 7){ cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; cell.backgroundColor = [UIColor purpleColor]; } else{ cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;//有俩图标。 cell.backgroundColor = [UIColor brownColor]; } return cell; }
设置背景
backgroundView cell.backgroundView
设置被选中时的背景视图
selectedBackgroundView cell.selectedBackgroundView
selectionStyle属性可设置UITableViewCell被选中时的背景颜色:
UITableViewCellSelectionStyleNone 没有颜色
UITableViewCellSelectionStyleBlue 蓝色(默认)
UITableViewCellSelectionStyleGray 灰色
UITableViewCell还有许多设置属性,需要的可以看一下源代码。
设置每行的高度
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return 40+3*index.row; }
效果图:
设置内容缩进
- (NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath{ return indexPath.row; }
效果:
选中一行响应事件,我们设置让其弹一个对话框,显示点击行的名字。
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:nil delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK",nil]; alert.title = [[_arrayHeros objectAtIndex:indexPath.row] name]; [alert show];//显示对话框 }
[_tableView reloadData]; // 整体刷新(每一行都会刷新)
//只刷新某行。 [_tableView reloadRowsAtIndexPaths:indexPath withRowAnimation:UITableViewRowAnimationLeft];我们只需要在相遇刷新的地方调用这个就可以重新加载UITableViewCell了。
右侧索引条,可以直接调整到对应位置。
代码如下:
HeroGroup.h
#import <Foundation/Foundation.h> @interface HeroGroup : NSObject //头部 @property (nonatomic, copy) NSString *header; //尾部 @property (nonatomic, copy) NSString *footer; //名字 @property (nonatomic, copy) NSArray *names; //图标 @property (nonatomic, copy) NSArray *icons; + (HeroGroup *)heroGroupWithHeader:(NSString *)header footer:(NSString *)footer names:(NSArray *)names icons:(NSArray *)icons; @end
#import "HeroGroup.h" @implementation HeroGroup + (HeroGroup *)heroGroupWithHeader:(NSString *)header footer:(NSString *)footer names:(NSArray *)names icons:(NSArray *)icons{ HeroGroup *hg = [[HeroGroup alloc] init]; hg.header = header; hg.footer = footer; hg.names = names; hg.icons = icons; return hg; } @end
#import <UIKit/UIKit.h> @interface GroupTabViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>{ UITableView *_tableView; NSArray *_heroAry; } @end
#import "GroupTabViewController.h" #import "HeroGroup.h" @interface GroupTabViewController () @end @implementation GroupTabViewController - (void)viewDidLoad { [super viewDidLoad]; CGRect frame = self.view.bounds; frame.origin.y = 20; //设置y坐标起始位置,否则会和状态栏重合。 _tableView = [[UITableView alloc]initWithFrame:frame style:UITableViewStyleGrouped]; _tableView.dataSource = self; _tableView.delegate = self; [self.view addSubview:_tableView]; [self initData]; } #pragma mark 初始化数据。 - (void)initData { // HeroGroup hg = [HeroGroup heroGroupWithHeader:(NSString *)header footer:(NSString *)footer names:(NSArray *)names icons:(NSArray *)icons; HeroGroup *top = [HeroGroup heroGroupWithHeader:@"上单" footer:@"上单很猛" names:@[@"剑姬",@"武器",@"人马"] icons:@[@"jianji.png",@"wuqi.png",@"renma.png"]]; HeroGroup *jungle = [HeroGroup heroGroupWithHeader:@"打野" footer:@"打野带动节奏" names:@[@"盲僧",@"蜘蛛",@"挖掘机"] icons:@[@"mangseng.png",@"zhizhu.png",@"wajueji.png"]]; HeroGroup *mid = [HeroGroup heroGroupWithHeader:@"中单" footer:@"中单爆发" names:@[@"妖姬",@"卡牌",@"发条"] icons:@[@"yaoji.png",@"kapai.png",@"fatiao.png"]]; HeroGroup *adc = [HeroGroup heroGroupWithHeader:@"ADC" footer:@"ADC持续输出" names:@[@"薇恩",@"金克丝"] icons:@[@"vn.png",@"jinkesi.png"]]; HeroGroup *support = [HeroGroup heroGroupWithHeader:@"辅助" footer:@"辅助很肉" names:@[@"牛头",@"石头人"] icons:@[@"niutou.png",@"shitouren.png"]]; _heroAry = @[top,jungle,mid,adc,support]; } #pragma mark 返回分组数 -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ return _heroAry.count; } #pragma mark 返回每组行数 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ HeroGroup *hg = _heroAry[section]; return hg.names.count; } #pragma mark 返回每行的单元格 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ HeroGroup *hg = _heroAry[indexPath.section]; UITableViewCell *cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil]; cell.textLabel.text=[hg.names objectAtIndex:indexPath.row]; cell.imageView.image =[UIImage imageNamed:hg.icons[indexPath.row]]; return cell; } #pragma mark 返回每组头标题名称 -(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{ HeroGroup *hg = _heroAry[section]; return hg.header; } #pragma mark 返回每组尾部说明 -(NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section{ HeroGroup *hg = _heroAry[section]; return hg.footer; } #pragma mark 返回每组标题索引 -(NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView{ NSMutableArray *indexs=[[NSMutableArray alloc]init]; for(HeroGroup *hg in _heroAry){ [indexs addObject:hg.header]; } return indexs; } #pragma mark - 代理方法 #pragma mark 设置分组头部内容高度 -(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{ return 40; } #pragma mark 设置每行高度(每行高度可以不一样) -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ return 45; } #pragma mark 设置尾部说明内容高度 -(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{ return 40; } @end
代码下载:点击打开链接