首页 > 代码库 > 第08章 表视图UITableView简介

第08章 表视图UITableView简介

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
 
 
 

第08章 表视图UITableView简介