UITableView表视图
UITableViewCell表视图单元
UITableViewDelegate
UITableViewDataSource
可以在UITableViewCell中添加子视图,从而在一个单元中放置更多的数据。
可以通过代码,或者在nib文件中加载他们。
两种基本样式:
分组表(grouped table):每个组都由嵌入在圆角矩形中的多个行组成。
无格式表(plain table):默认的样式,没有圆角矩形,如果使用了索引,又称为索引表。
表中的每个部分,称为数据源中的分区(section)。
分组表中,每个分组都是一个分区。
索引表中,每个索引都是一个分区。
iphone human interface guidelines中,不建议创建带有索引的分组表。
关键词
UITableView
- (void)registerClass:(Class
)cellClass
forCellReuseIdentifier:(NSString *
)identifier
- (id)dequeueReusableCellWithIdentifier:(NSString *
)identifier
UITableViewCell
textLabel
NSIndexPath
section
row
UITableViewDataSource
numberOfRowsInSection
cellForRowAtIndexPath
UITableViewDelegate
willSelectRowAtIndexPath
didSelectRowAtIndexPath
一个简单的表视图例子
1. 使用模板single view application创建工程
2. 向xib中拖入一个table view 实例,并关联委托和数据源到file‘s owner
?
Table View Data Source数据源方法
static NSString *simpleTableIdentifier = @"SimpleTableIdentifier";
[self.tableView registerClass:[UITableViewCell class]
forCellReuseIdentifier:@"HYDTableViewCell"];
获取某个分区中,有多少行
-(NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
获取某个分区中的某行的表视图单元
-(UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = @"SimpleTableIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
//if (cell==nil) {
// cell = [[UITableViewCell alloc]
// initWithStyle:UITableViewCellStyleDefault
// reuseIdentifier:simpleTableIdentifier];
//}
cell.textLabel.text = self.dwarves[indexPath.row];
return cell;
}
NSIndexPath:row,section
dequeueReusableCellWithIdentifier为表视图单元重新利用
当表视图单元滚离屏幕时,它们将被放置在一个可重用的单元队列中,以便后面重新利用,避免了重复创建和销毁。
如果系统运行较慢,则会清理这些单元,以释放存储空间。
添加一个图像
UIImage *image = [UIImage imageNamed:@"star.png"];
UIImage *highlightImage = [UIImage imageNamed:@"star2.png"];
cell.imageView.image = image;
cell.imageView.highlightedImage = highlightImage;
UITableViewCell属性
imageView:文本左侧的图像
textLable:文本
detailTextLable:详细文本,通常用作解释性的说明
自带样式
UITableViewCellStyleDefault:默认样式,只显示左侧图像和文本
UITableViewCellStyleSubtitle:在文本下方显示详细文本
UITableViewCellStyleValue1:在右侧显示详细文本
UITableViewCellStyleValue2:不显示图像,并将详细文本粗体显示在文本右边(居中)
以上都为数据源方法,用来向表视图提供数据。
下面介绍委托方法,来控制表示图的外观和处理用户交互
控制缩进:
-(NSInteger)tableView:(UITableView *)tableView
indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath
更改字体大小和行高
表视图自身有个rowHeight属性,其控制所有行的行高
而这个委托方法,可控制某行的行高
cell.textLabel.font = [UIFont systemFontOfSize:50];
- (CGFloat)tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath
选中:
某行将会被选中
-(NSIndexPath *)tableView:(UITableView *)tableView
willSelectRowAtIndexPath:(NSIndexPath *)indexPath
某行已经被选中
-(void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
定制表示图单元:
代码方式(其实就是添加UITableViewCell子类,然后向其添加子视图)
1.通过single view application创建xcode项目Cells
2.添加新单元:创建类BIDNameAndColorCell,继承自UITableViewCell
3.为cell添加子视图
改写如下方法
- (id)initWithStyle:(UITableViewCellStyle)style
reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
//添加子视图
CGRect nameLabelRect = CGRectMake(0, 5, 70, 15);
UILabel *nameLabel = [[UILabel alloc] initWithFrame: nameLabelRect];
nameLabel.textAlignment = NSTextAlignmentRight;
nameLabel.text = @"Name:";
nameLabel.font = [UIFont systemFontOfSize:12];
[self.contentView addSubview: nameLabel];
………
}}
此时通常会遇到一个问题,cell中某些控件的值,通常是需要用户在创建出此cell后,通过cell属性来设置,
而初始化此cell的时候,这些暴露给用户的属性暂时为空的,用户还没来得及设置,
解决此问题的办法是,修改这些属性的setter,当用户设置或者修改这些属性的时候,将值重新赋给控件的某个属性。
那么此时,就需要在代码中获取某子视图的指针,以往在c++中通常是定义一个私有指针变量,来保持此变量
在oc也一样,定义一个控件的私有变量,注意,定义为私有,就会不会暴漏给外部,
此时只需要定义为实例变量即可,而不需要使用property,不过其实也可以定义为私有的outlet
类的数据成员,在类中,直接访问, _XXX
类的属性,在类中,使用self.xxx访问
如果需要在控制器类的.m中获取某子视图指针,有两种方法:
1.为此子视图定义输出口,关联xib文件中子视图实例(此种方法,外部可获取到此子视图属性)
2.为其定义私有的输出口(在.m无名类扩展中)
3.UITableView *tableView = (id)[self.view viewWithTag:1];
其实就类似与MFC,当想让外界访问到子控件时,定义成员变量,DDX/DDV
外界不需要访问此子控件,而内部又要使用的时候,采用GetDlgItem获取
关于cell 的reuse
1.提前在viewDidLoad中,通过tableView为某类型的cell,注册可重用标识符
[tableView registerClass:[BIDNameAndColorCell class]
forCellReuseIdentifier:@"HYDCELL"];
此时,以后采用dequeueReusableCellWithIdentifier所获取的cell肯定非空,不用判空。
2.采用之前的方法,不在viewDidLoad中提前注册,而是在init cell的时候,为其设置可重用标识符
static NSString *simpleTableIdentifier = @"HYDCELL";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell==nil) {
cell = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:simpleTableIdentifier];
}
但是有个问题,此时传入的类型UITableViewCellStyleDefault起什么作用?所以说,如果是定制类型的cell,不应该采用此方法。
应该统一在viewDidLoad中,
采用registerClass: forCellReuseIdentifier为纯代码的Cell注册可重用标识符,
采用registerNib: forCellReuseIdentifier为xib方式的Cell注册可重用标识符
xib方式(新建UITableViewCell子类,关联,注册xib文件)
1. 创建UITableViewCell子类BIDXibCell
2. 创建XibCell.xib
3. 拖入一个Table View Cell
4. 修改关联类型为BIDXibCell,修改行高为65, 修改其可重用标识符
注意,在表视图中,还应该使用viewTable的属性rowHeight修改表视图的行高,表视图单元的行高和表视图的行高是两个概念。
而且,表视图的行高属性,修改后,则所有行统一修改。
使用委托方法,heightForRowAtIndexpath,则可修改某行的高度
5. 拖入子控件,向其关联的自定义类型中关联输出口
6. 为此xib定义的表视图单元注册可重用标识符(viewDidLoad中)
UINib *nib = [UINib nibWithNibName:@"XibCell" bundle:nil];
[self.tableView registerNib: nib forCellReuseIdentifier:@"CellTableIdentifire”];
最后,回过头来,哪种方式定义的cell比较好?
个人认为是纯代码方式,因为这种好复用,只有一个类型,不像xib方式,还得绑定一个xib文件。
分组表,多分区
使用Single View Application创建工程,Sections
向xib中拖入一个table view,格式改为grouped
将名为sortednames.plist(单词表)的文件拖入工程
@property (copy, nonatomic) NSDictionary *names; //all data
@property (copy, nonatomic) NSArray *keys; //all keys
- (void)viewDidLoad
{
[super viewDidLoad];
UITableView *tableView = (id)[self.view viewWithTag:1];
[tableView registerClass:[UITableViewCell class]
forCellReuseIdentifier:SectionsTableIdentifier];
NSString *path = [[NSBundle mainBundle] pathForResource:@"sortednames" ofType:@"plist"];
self.names = [NSDictionary dictionaryWithContentsOfFile: path];
self.keys = [[self.names allKeys] sortedArrayUsingSelector: @selector(compare:)];
}
#pragma mark -
#pragma mark Table View Data Source Methods
//分区数量
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView ;
//某个分区的行数
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section ;
//某个分区的title
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;
//获取某个位置的表视图单元
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath;
其实创建多个分区很简单,实现响应的数据源方法即可。
索引表
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
return self.keys;
}
添加索引更简单,实现以上数据源方法即可。
The returned array must have the same number of entries as you have sections, and the values must correspond to the appropriate section.
不过此数组需要跟表视图中,各分区完全匹配。
总结:
1.大量的委托方法,实现tableView的数据源和委托
2.自定义的Controller,关联一个xib,其中有一个UITableView
此时,如果要自定义Cell样式,有两种方法:
2.1.代码方式,创建UITableViewCell子类,在其init中添加子视图,
在controller中的viewDidLoad中为此cell registerClass,进而可以获取到该类型的cell
2.2.xib方式,创建一个xib,包含一个UITableViewCell, 利用IB修改界面
然后在controller中的viewDidLoad中为此cell registerNib,进而可以获取到该类型的cell