UITableView使用
2015-07-06 22:56
711 查看
一:UITableView基础知识点。
首先理解各个代理方法的调用顺序,这对于开发非常重要,理解好这一点,在项目开发中将会节省很多时间。下面我们一起来看一下,错误的地方,希望大家指出,一起学习。(最好的理解方式就是自己写一个小demo)
//情况一:单分区情况
1)首先调用-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView方法计算UITableView中分区的个数.
2)执行-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section方法,计算每个分区中row的个数.
3)计算每个cell的高度,cell有多少个,该方法-
(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath就被执行多少次.上面过程被反复执行了3次.
4)然后调用-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath
*)indexPath创建cell,和显示cell的内容.屏幕中可以显示多少个cell,该方法就会被调用多少次.并且同时还会调用计算高度方法计算该cell的高度.
5)当滚动屏幕出现新的cell的时候,首先会先调用-(UITableViewCell
*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath显示cell的内容.然后立马计算 cell的高度.
[self.tableView reloadData];使用该方法进行刷新数据的时候,会按照刚刚执行方法的顺序,再执行一次.
//多分区情况
1:
先确定分区个数调用该 -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView方法,及Section个数.
2:
调用-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
从scetion等于1开始(我这里是使用了2个分区,多分区从最后一个开始自动计算,依次向前).section为1时,计算分区中cell的高度,section为0时计算分区中cell的高度.
3:
然后调用-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath创建cell,和显示cell的内容.屏幕中可以显示多少个cell,该方法就会被调用多少次.从分区0开始,只计算屏幕上显示的内容.
4:滑动屏幕的时候,调用-(UITableViewCell
*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath显示内容,同时调用- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath
*)indexPath方法计算高度.
[self.tableView reloadData];使用该方法进行刷新数据的时候,会按照刚刚执行方法的顺序,再执行一次.
1)看代码理解基本的属性和方法,下面代码实现了最基本的列表展示,移动表格可看见分区头视图进行替换。
#import "RootViewController.h"
@interface
RootViewController ()
{
NSMutableArray *_dataArray;//数据源:给UITableView提供数据
}
@end
@implementation RootViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle
*)nibBundleOrNil
{
self = [superinitWithNibName:nibNameOrNilbundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return
self;
}
- (void)viewDidLoad
{
[superviewDidLoad];
//准备数据
_dataArray = [[NSMutableArrayalloc]init];
//实现通讯录的展示
for (int i='A'; i<='Z';i++)
{
NSMutableArray *array = [[NSMutableArrayalloc]init];
for (int j=0; j<10;
j++) {
NSString *str = [NSStringstringWithFormat:@"%c%d",i,j];
[arrayaddObject:str];
}
[_dataArrayaddObject:array];
}
self.automaticallyAdjustsScrollViewInsets =NO;
//表视图,是一个特殊的UIScrollView,默认横向固定,纵向可以上下滚动,contentSize自动计算
//创建tableView并设置样式(常规的样式)
//表示图,是一个特殊到uiscrollview,默认横向固定,纵向可以上下滚动。contentsize自动计算,不需要你来设置。UITableViewStylePlain常规显示样式。
UITableView *tableView = [[UITableViewalloc]initWithFrame:CGRectMake(0,0,self.view.bounds.size.width,self.view.bounds.size.height-64)style:UITableViewStylePlain];
//设置代理 (代理方法都是与tableView UI样式相关的方法)//设置tabview都数据源,协议中有2个必须实现都方法,所以要记住,使用来数据源加要注意方法实现,而且很重要。
tableView.delegate =self;
//设置tableView的数据源(数据源方法一般都是与UITableView数据操作有关的方法)
tableView.dataSource =self;
[self.viewaddSubview:tableView];
}
#pragma mark - UITableViewDelegate
//设置行高,不写此方法,默认高度44
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath
*)indexPath{
return50;
}
//选中tableView中的某一行时,触发此方法
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
*)indexPath{
NSLog(@"selected section:%d row:%d",indexPath.section,indexPath.row);
//通过tableView设置某一行,自动反选,反选的代理方法不再被调用
[tableView deselectRowAtIndexPath:indexPathanimated:YES];
//这里一般情况下是push到下一级进行相应的操作。
}
//某一行被反选时,触发此方法当某一行由选中变为非选中状态会调用此方法。
//即某一行被反选时,触发次方法
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath
*)indexPath{
NSLog(@"deselect section:%d row:%d",indexPath.section,indexPath.row);
}
#pragma mark - UITableViewDataSource
//告诉tableView有多少个分区(数据有多少类)
//如果不写此方法,默认tableView有一个分区
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return_dataArray.count;
}
//告诉tableView每个分区有多少条(行)数据
//有多少个分区
此方法被执行多少次,section在方法执行时从0自增
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [[_dataArrayobjectAtIndex:section]count];
}
//tableView中每一行都是一个UITableViewCell对象:单元格,本质上是一个视图
//一开始,屏幕中可见多少行,此方法被调用多少次,当上、下滑动屏幕时,此方法也会被调用
//cell的重用机制保证了只创建有限个cell对象,来显示多条数据,最大限度的节省了内存的开销,提高了程序的运行效率,具有极大的借鉴意义
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath
*)indexPath{
staticNSString *cellIde =@"Cell";//声明cell的可重用标识符
//根据可重用标识符,到tableView的重用队列中,取cell对象
UITableViewCell *cell = [tableViewdequeueReusableCellWithIdentifier:cellIde];
if (cell ==nil) {
//如果取不到,则创建新的cell对象
//创建cell设置样式,并赋值可重用标识符
cell = [[UITableViewCellalloc]initWithStyle:UITableViewCellStyleSubtitlereuseIdentifier:cellIde];
}
//设置cell的选中样式,iOS7之前,cell的选中样式默认为蓝色,iOS7之后
cell.selectionStyle =UITableViewCellSelectionStyleGray;
//设置cell右侧的提示样式
//UITableViewCellAccessoryDisclosureIndicator箭头提示
cell.accessoryType =UITableViewCellAccessoryDisclosureIndicator;
//将数据,赋值给cell
//indexPath section带有该行所在的分区信息 row该行在对应分区的位置
//取到该分区所使用的数组
NSArray *array = [_dataArrayobjectAtIndex:indexPath.section];
NSString *str = [arrayobjectAtIndex:indexPath.row];
//将数组赋值给cell
//UITableViewCellStyleSubtitle
副标题才能显示
//设置cell的主标题
cell.textLabel.text = str;
//设置副标题
cell.detailTextLabel.text =@"test";
//设置图片(头像)
cell.imageView.image = [UIImageimageNamed:@"0.png"];
return cell;
}
//设置分区的头标题
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
return [NSStringstringWithFormat:@"第%c分区头标",'A'+section];
}
二:项目中常用到UITableView的一些小知识点:
1)UITableViewCell横线左端对其实现:
方法一:在初始化的表格的时候添加如下代码
if ([_tableViewrespondsToSelector:@selector(setSeparatorInset:)])
{
[_tableViewsetSeparatorInset:UIEdgeInsetsZero];
}
if ([_tableViewrespondsToSelector:@selector(setLayoutMargins:)])
{
[_tableViewsetLayoutMargins:UIEdgeInsetsZero];
}
实现代理方法
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell
*)cell forRowAtIndexPath:(NSIndexPath *)indexPath{
if ([cellrespondsToSelector:@selector(setSeparatorInset:)])
{
[cellsetSeparatorInset:UIEdgeInsetsZero];
}
if ([cellrespondsToSelector:@selector(setLayoutMargins:)])
{
[cellsetLayoutMargins:UIEdgeInsetsZero];
}
}
方法二:去除表格细线,然后自定义细线进行添加
_tableView.separatorStyle =UITableViewCellSeparatorStyleNone;
//添加细线
CALayer *lineLayer=[CALayerlayer];
lineLayer.frame=CGRectMake(0,43.5,self.view.bounds.size.width,0.5);//位置根据需求自己设置
lineLayer.backgroundColor=[UIColorgrayColor].CGColor;
[self.view.layeraddSublayer:lineLayer];
2)取消点击cell时候的背景效果。
cell.selectionStyle=UITableViewCellSeparatorStyleNone;
//选中tableView中的某一行时,触发此方法
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
*)indexPath{
//通过tableView设置某一行,自动反选,反选的代理方法不再被调用
[tableView deselectRowAtIndexPath:indexPathanimated:YES];
}
3)去除尾部多余的cell
self.tableView.tableFooterView=[[UIView alloc]init];//一句话解决问题
4)实现添加删除cell的动画效果,beginUpdates方法和endUpdates方法。
这两个方法,是配合起来使用的,标记了一个tableView的动画块。分别代表动画的开始开始和结束。
两者成对出现,可以嵌套使用。一般,在添加,删除,选择 tableView中使用,并实现动画效果。
在动画块内,不建议使用reloadData方法,如果使用,会影响动画。
插入指定的行,
在执行该方法时,会对数据源进行访问(分组数据和行数据),并更新可见行。所以,在调用该方法前,应该先更新数据源
- (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
插入分组到制定位置
- (void)insertSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation
插入一个特定的分组。如果,指定的位置上已经存在了分组,那么原来的分组向后移动一个位置。
删除制定位置的分组
- (void)deleteSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation
删除一个制定位置的分组,其后面的分组向前移动一个位置。
删除选择的row
- (void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
移动分组
- (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection
移动原来的分组从一个位置移动到一个新的位置。如果,新位置上若存在某个分组,那这某个分组将会向上(下)移动到临近一个位置。该方法,没有动画参数。会直接移动。并且一次只能移动一个分组。
在如上方法中,建议使用该动画块进行操作!
具体实现部分代码:
删除部分操作:(插入原理其实是一样的,保证数据源随之更新即可)
[self.tableViewbeginUpdates];
//要记得对分区进行删除操作。self.dataArray是一个二维数组。及实现多分区情况下的删除操纵。
if([[self.dataArrayobjectAtIndex:
indexPath.section]count] >
1)
{
[_tableViewdeleteRowsAtIndexPaths:[NSArrayarrayWithObject:[NSIndexPathindexPathForRow:indexPath.rowinSection:indexPath.section]]withRowAnimation:UITableViewRowAnimationLeft];
}
else
{
//如果我们的UITableView是分组的时候,我们如果删除某个分组的最后一条记录时,相应的分组也将被删除。所以,必须保证UITableView的分组,和cell同时被删除。
[_tableViewdeleteSections:[NSIndexSetindexSetWithIndex:indexPath.section]
withRowAnimation:UITableViewRowAnimationLeft];
}
//注意:数据源在beginUpdates前面操作和在后面操作,并没有什么关系,关键一点是数据源要随着删除,插入的数据与之对应改变,不然就会出现错误。但是不能够把对数据源的操作放到endUpdates。
NSMutableArray *arr=self.dataArray[indexPath.section];
[arrremoveObjectAtIndex:indexPath.row];
[self.dataArrayremoveObjectAtIndex:indexPath.section];
if(arr.count!=0)
[self.dataArrayinsertObject:arr
atIndex:indexPath.section];
[self.tableViewendUpdates];
5)UITableViewCell重用原理
重用原理:当滚动列表时,部分UITableViewCell会移出窗口,UITableView会将窗口外的UITableViewCell放入一个对象池中,等待重用。当UITableView要求dataSource返回UITableViewCell时,dataSource会先查看这个对象池,如果池中有未使用的UITableViewCell,dataSource会用新的数据配置这个UITableViewCell,然后返回给UITableView,重新显示到窗口中,从而避免创建新对象。
重用代码,大家应该是非常熟悉的:如下:
static NSString *cellIde =@"Cell";//声明cell的可重用标识符
//根据可重用标识符,到tableView的重用队列中,取cell对象
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIde];
if (cell == nil) {
//如果取不到,则创建新的cell对象,创建cell设置样式,并赋值可重用标识符
cell = [[[UITableViewCellalloc] initWithStyle:UITableViewCellStyleSubtitlereuseIdentifier:cellIde]autorelease];
}
但有时候系统自带的cell无法满足需求的时候,需要自定义UITableViewCell(用一个子类继承UITableViewCell,自定义UITableViewCell很重要,要掌握),而且每一行用的不一定是同一种UITableViewCell,所以一个UITableView可能拥有不同类型的UITableViewCell,对象池中也会有很多不同类型的UITableViewCell,那么UITableView在重用UITableViewCell时可能会得到错误类型的UITableViewCell。
解决方案:UITableViewCell有个NSString *reuseIdentifier属性,可以在初始化UITableViewCell的时候传入一个特定的字符串标识来设置reuseIdentifier9。当UITableView要求dataSource返回UITableViewCell时,先通过一个字符串标识到对象池中查找对应类型的UITableViewCell对象,如果有,就重用,如果没有,就传入这个字符串标识来初始化一个UITableViewCell对象。
重用UITableViewCell对象:
在ios5
和io6中分别提供了方法可以先注册cell,注册后就不需要在判断cell是否为空
- (void)registerNib:(UINib *)nib forCellReuseIdentifier:(NSString *)identifierNS_AVAILABLE_IOS(5_0);
- (void)registerClass:(Class)cellClass forCellReuseIdentifier:(NSString *)identifierNS_AVAILABLE_IOS(6_0);
注:
去对象池中取可重用的cell,系统提供了2个方法,分别是
- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier;
- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath
*)indexPath NS_AVAILABLE_IOS(6_0);
这2个方法如果在已经注册的情况下作用是一样的。
区别在于后一个方法会强制需要注册,否则会报错,即使代码中有判断cell为空得情况。
2 自定义UITableViewCell
一般有两种方式:
①用一个xib文件来描述UITableViewCell的内容。
②通过代码往UITableViewCell的contentView中添加子视图,在初始化方法(比如init、initWithStyle:reuseIdentifier:)中添加子控件,在layoutSubviews方法中分配子控件的位置和大小。
方法一:
1:首先计算需要显示在界面上cell的大小,然后显示相应的内容。当新出现一个cell的时候,去重用列队拿一个cell。然后去除上面显示的所有子视图(但是这样创建对象的消耗也会相应增加)。在重新创建对应位置的控件,进行赋值操作。
2:在初始化的时候,只需要创建对应的控件即可。然后在进行数据操作的时候设置相应控件的参数。
3:出现新cell的时候机会先调用显示,然后在调用高度。所以只要保证先获取对应位置cell的高度,然后在对各个控件进行赋值操作。
注意:每一个控件都要是全局的变量,这样才可以在该界面一直使用。
6)在表格视图界面点击一个按钮回到最开始的cell
- (void)scrollToRowAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated;//使用这个方法即可
[tableView scrollToRowAtIndexPath:[NSIndexPathindexPathForRow:0inSection:0]
atScrollPosition:UITableViewScrollPositionTop animated:YES];//就是这个效果点击
button 之后回到顶部
7):在UITableviewCell上知道自己点击了哪一个 button
-(void)buttonPressed:(id)sender { //button点击事件
UITableViewCell *clickedCell = (UITableViewCell *)[[sender superview] superview];
NSIndexPath *clickedButtonPath = [self.tableView indexPathForCell:clickedCell];
...
}
方法二:
- (void)buttonTappedAction:(id)sender {
CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:buttonPosition];
...
}
8) 删除重用的cell的所有子视图
从而得到一个没有特殊格式的cell,供其他cell重用。(可以很好的把对cell有过操作的效果全部去掉,然后拿过来重新使用,要保持之前的状态,只需要之前先存储好,在调用代理方法的时候获取数据显示即可)
if (cell ==
nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier];
}
else
{
//删除cell的所有子视图
while ([cell.contentView.subviews lastObject] !=nil)
{
[(UIView*)[cell.contentView.subviews lastObject] removeFromSuperview];
}
}
9)获取对应位置cell的方法.
NSIndexPath *cellIndexPath=[NSIndexPath
indexPathForRow:indexPath.row inSection:indexPath.section];
UITableViewCell *cell=[tableViewcellForRowAtIndexPath:cellIndexPath];
10)
设置tableViewCell间的分割线的颜色
[tableView setSeparatorColor:[UIColorredColor]];
改变UITableViewCell选中时背景色:
cell.selectedBackgroundView = [[UIView alloc] initWithFrame:cell.frame];
cell.selectedBackgroundView.backgroundColor = [UIColorredColor];
首先理解各个代理方法的调用顺序,这对于开发非常重要,理解好这一点,在项目开发中将会节省很多时间。下面我们一起来看一下,错误的地方,希望大家指出,一起学习。(最好的理解方式就是自己写一个小demo)
//情况一:单分区情况
1)首先调用-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView方法计算UITableView中分区的个数.
2)执行-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section方法,计算每个分区中row的个数.
3)计算每个cell的高度,cell有多少个,该方法-
(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath就被执行多少次.上面过程被反复执行了3次.
4)然后调用-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath
*)indexPath创建cell,和显示cell的内容.屏幕中可以显示多少个cell,该方法就会被调用多少次.并且同时还会调用计算高度方法计算该cell的高度.
5)当滚动屏幕出现新的cell的时候,首先会先调用-(UITableViewCell
*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath显示cell的内容.然后立马计算 cell的高度.
[self.tableView reloadData];使用该方法进行刷新数据的时候,会按照刚刚执行方法的顺序,再执行一次.
//多分区情况
1:
先确定分区个数调用该 -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView方法,及Section个数.
2:
调用-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
从scetion等于1开始(我这里是使用了2个分区,多分区从最后一个开始自动计算,依次向前).section为1时,计算分区中cell的高度,section为0时计算分区中cell的高度.
3:
然后调用-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath创建cell,和显示cell的内容.屏幕中可以显示多少个cell,该方法就会被调用多少次.从分区0开始,只计算屏幕上显示的内容.
4:滑动屏幕的时候,调用-(UITableViewCell
*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath显示内容,同时调用- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath
*)indexPath方法计算高度.
[self.tableView reloadData];使用该方法进行刷新数据的时候,会按照刚刚执行方法的顺序,再执行一次.
1)看代码理解基本的属性和方法,下面代码实现了最基本的列表展示,移动表格可看见分区头视图进行替换。
#import "RootViewController.h"
@interface
RootViewController ()
{
NSMutableArray *_dataArray;//数据源:给UITableView提供数据
}
@end
@implementation RootViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle
*)nibBundleOrNil
{
self = [superinitWithNibName:nibNameOrNilbundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return
self;
}
- (void)viewDidLoad
{
[superviewDidLoad];
//准备数据
_dataArray = [[NSMutableArrayalloc]init];
//实现通讯录的展示
for (int i='A'; i<='Z';i++)
{
NSMutableArray *array = [[NSMutableArrayalloc]init];
for (int j=0; j<10;
j++) {
NSString *str = [NSStringstringWithFormat:@"%c%d",i,j];
[arrayaddObject:str];
}
[_dataArrayaddObject:array];
}
self.automaticallyAdjustsScrollViewInsets =NO;
//表视图,是一个特殊的UIScrollView,默认横向固定,纵向可以上下滚动,contentSize自动计算
//创建tableView并设置样式(常规的样式)
//表示图,是一个特殊到uiscrollview,默认横向固定,纵向可以上下滚动。contentsize自动计算,不需要你来设置。UITableViewStylePlain常规显示样式。
UITableView *tableView = [[UITableViewalloc]initWithFrame:CGRectMake(0,0,self.view.bounds.size.width,self.view.bounds.size.height-64)style:UITableViewStylePlain];
//设置代理 (代理方法都是与tableView UI样式相关的方法)//设置tabview都数据源,协议中有2个必须实现都方法,所以要记住,使用来数据源加要注意方法实现,而且很重要。
tableView.delegate =self;
//设置tableView的数据源(数据源方法一般都是与UITableView数据操作有关的方法)
tableView.dataSource =self;
[self.viewaddSubview:tableView];
}
#pragma mark - UITableViewDelegate
//设置行高,不写此方法,默认高度44
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath
*)indexPath{
return50;
}
//选中tableView中的某一行时,触发此方法
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
*)indexPath{
NSLog(@"selected section:%d row:%d",indexPath.section,indexPath.row);
//通过tableView设置某一行,自动反选,反选的代理方法不再被调用
[tableView deselectRowAtIndexPath:indexPathanimated:YES];
//这里一般情况下是push到下一级进行相应的操作。
}
//某一行被反选时,触发此方法当某一行由选中变为非选中状态会调用此方法。
//即某一行被反选时,触发次方法
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath
*)indexPath{
NSLog(@"deselect section:%d row:%d",indexPath.section,indexPath.row);
}
#pragma mark - UITableViewDataSource
//告诉tableView有多少个分区(数据有多少类)
//如果不写此方法,默认tableView有一个分区
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return_dataArray.count;
}
//告诉tableView每个分区有多少条(行)数据
//有多少个分区
此方法被执行多少次,section在方法执行时从0自增
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [[_dataArrayobjectAtIndex:section]count];
}
//tableView中每一行都是一个UITableViewCell对象:单元格,本质上是一个视图
//一开始,屏幕中可见多少行,此方法被调用多少次,当上、下滑动屏幕时,此方法也会被调用
//cell的重用机制保证了只创建有限个cell对象,来显示多条数据,最大限度的节省了内存的开销,提高了程序的运行效率,具有极大的借鉴意义
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath
*)indexPath{
staticNSString *cellIde =@"Cell";//声明cell的可重用标识符
//根据可重用标识符,到tableView的重用队列中,取cell对象
UITableViewCell *cell = [tableViewdequeueReusableCellWithIdentifier:cellIde];
if (cell ==nil) {
//如果取不到,则创建新的cell对象
//创建cell设置样式,并赋值可重用标识符
cell = [[UITableViewCellalloc]initWithStyle:UITableViewCellStyleSubtitlereuseIdentifier:cellIde];
}
//设置cell的选中样式,iOS7之前,cell的选中样式默认为蓝色,iOS7之后
cell.selectionStyle =UITableViewCellSelectionStyleGray;
//设置cell右侧的提示样式
//UITableViewCellAccessoryDisclosureIndicator箭头提示
cell.accessoryType =UITableViewCellAccessoryDisclosureIndicator;
//将数据,赋值给cell
//indexPath section带有该行所在的分区信息 row该行在对应分区的位置
//取到该分区所使用的数组
NSArray *array = [_dataArrayobjectAtIndex:indexPath.section];
NSString *str = [arrayobjectAtIndex:indexPath.row];
//将数组赋值给cell
//UITableViewCellStyleSubtitle
副标题才能显示
//设置cell的主标题
cell.textLabel.text = str;
//设置副标题
cell.detailTextLabel.text =@"test";
//设置图片(头像)
cell.imageView.image = [UIImageimageNamed:@"0.png"];
return cell;
}
//设置分区的头标题
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
return [NSStringstringWithFormat:@"第%c分区头标",'A'+section];
}
二:项目中常用到UITableView的一些小知识点:
1)UITableViewCell横线左端对其实现:
方法一:在初始化的表格的时候添加如下代码
if ([_tableViewrespondsToSelector:@selector(setSeparatorInset:)])
{
[_tableViewsetSeparatorInset:UIEdgeInsetsZero];
}
if ([_tableViewrespondsToSelector:@selector(setLayoutMargins:)])
{
[_tableViewsetLayoutMargins:UIEdgeInsetsZero];
}
实现代理方法
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell
*)cell forRowAtIndexPath:(NSIndexPath *)indexPath{
if ([cellrespondsToSelector:@selector(setSeparatorInset:)])
{
[cellsetSeparatorInset:UIEdgeInsetsZero];
}
if ([cellrespondsToSelector:@selector(setLayoutMargins:)])
{
[cellsetLayoutMargins:UIEdgeInsetsZero];
}
}
方法二:去除表格细线,然后自定义细线进行添加
_tableView.separatorStyle =UITableViewCellSeparatorStyleNone;
//添加细线
CALayer *lineLayer=[CALayerlayer];
lineLayer.frame=CGRectMake(0,43.5,self.view.bounds.size.width,0.5);//位置根据需求自己设置
lineLayer.backgroundColor=[UIColorgrayColor].CGColor;
[self.view.layeraddSublayer:lineLayer];
2)取消点击cell时候的背景效果。
cell.selectionStyle=UITableViewCellSeparatorStyleNone;
//选中tableView中的某一行时,触发此方法
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
*)indexPath{
//通过tableView设置某一行,自动反选,反选的代理方法不再被调用
[tableView deselectRowAtIndexPath:indexPathanimated:YES];
}
3)去除尾部多余的cell
self.tableView.tableFooterView=[[UIView alloc]init];//一句话解决问题
4)实现添加删除cell的动画效果,beginUpdates方法和endUpdates方法。
这两个方法,是配合起来使用的,标记了一个tableView的动画块。分别代表动画的开始开始和结束。
两者成对出现,可以嵌套使用。一般,在添加,删除,选择 tableView中使用,并实现动画效果。
在动画块内,不建议使用reloadData方法,如果使用,会影响动画。
插入指定的行,
在执行该方法时,会对数据源进行访问(分组数据和行数据),并更新可见行。所以,在调用该方法前,应该先更新数据源
- (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
插入分组到制定位置
- (void)insertSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation
插入一个特定的分组。如果,指定的位置上已经存在了分组,那么原来的分组向后移动一个位置。
删除制定位置的分组
- (void)deleteSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation
删除一个制定位置的分组,其后面的分组向前移动一个位置。
删除选择的row
- (void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
移动分组
- (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection
移动原来的分组从一个位置移动到一个新的位置。如果,新位置上若存在某个分组,那这某个分组将会向上(下)移动到临近一个位置。该方法,没有动画参数。会直接移动。并且一次只能移动一个分组。
在如上方法中,建议使用该动画块进行操作!
具体实现部分代码:
删除部分操作:(插入原理其实是一样的,保证数据源随之更新即可)
[self.tableViewbeginUpdates];
//要记得对分区进行删除操作。self.dataArray是一个二维数组。及实现多分区情况下的删除操纵。
if([[self.dataArrayobjectAtIndex:
indexPath.section]count] >
1)
{
[_tableViewdeleteRowsAtIndexPaths:[NSArrayarrayWithObject:[NSIndexPathindexPathForRow:indexPath.rowinSection:indexPath.section]]withRowAnimation:UITableViewRowAnimationLeft];
}
else
{
//如果我们的UITableView是分组的时候,我们如果删除某个分组的最后一条记录时,相应的分组也将被删除。所以,必须保证UITableView的分组,和cell同时被删除。
[_tableViewdeleteSections:[NSIndexSetindexSetWithIndex:indexPath.section]
withRowAnimation:UITableViewRowAnimationLeft];
}
//注意:数据源在beginUpdates前面操作和在后面操作,并没有什么关系,关键一点是数据源要随着删除,插入的数据与之对应改变,不然就会出现错误。但是不能够把对数据源的操作放到endUpdates。
NSMutableArray *arr=self.dataArray[indexPath.section];
[arrremoveObjectAtIndex:indexPath.row];
[self.dataArrayremoveObjectAtIndex:indexPath.section];
if(arr.count!=0)
[self.dataArrayinsertObject:arr
atIndex:indexPath.section];
[self.tableViewendUpdates];
5)UITableViewCell重用原理
重用原理:当滚动列表时,部分UITableViewCell会移出窗口,UITableView会将窗口外的UITableViewCell放入一个对象池中,等待重用。当UITableView要求dataSource返回UITableViewCell时,dataSource会先查看这个对象池,如果池中有未使用的UITableViewCell,dataSource会用新的数据配置这个UITableViewCell,然后返回给UITableView,重新显示到窗口中,从而避免创建新对象。
重用代码,大家应该是非常熟悉的:如下:
static NSString *cellIde =@"Cell";//声明cell的可重用标识符
//根据可重用标识符,到tableView的重用队列中,取cell对象
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIde];
if (cell == nil) {
//如果取不到,则创建新的cell对象,创建cell设置样式,并赋值可重用标识符
cell = [[[UITableViewCellalloc] initWithStyle:UITableViewCellStyleSubtitlereuseIdentifier:cellIde]autorelease];
}
但有时候系统自带的cell无法满足需求的时候,需要自定义UITableViewCell(用一个子类继承UITableViewCell,自定义UITableViewCell很重要,要掌握),而且每一行用的不一定是同一种UITableViewCell,所以一个UITableView可能拥有不同类型的UITableViewCell,对象池中也会有很多不同类型的UITableViewCell,那么UITableView在重用UITableViewCell时可能会得到错误类型的UITableViewCell。
解决方案:UITableViewCell有个NSString *reuseIdentifier属性,可以在初始化UITableViewCell的时候传入一个特定的字符串标识来设置reuseIdentifier9。当UITableView要求dataSource返回UITableViewCell时,先通过一个字符串标识到对象池中查找对应类型的UITableViewCell对象,如果有,就重用,如果没有,就传入这个字符串标识来初始化一个UITableViewCell对象。
重用UITableViewCell对象:
在ios5
和io6中分别提供了方法可以先注册cell,注册后就不需要在判断cell是否为空
- (void)registerNib:(UINib *)nib forCellReuseIdentifier:(NSString *)identifierNS_AVAILABLE_IOS(5_0);
- (void)registerClass:(Class)cellClass forCellReuseIdentifier:(NSString *)identifierNS_AVAILABLE_IOS(6_0);
注:
去对象池中取可重用的cell,系统提供了2个方法,分别是
- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier;
- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath
*)indexPath NS_AVAILABLE_IOS(6_0);
这2个方法如果在已经注册的情况下作用是一样的。
区别在于后一个方法会强制需要注册,否则会报错,即使代码中有判断cell为空得情况。
2 自定义UITableViewCell
一般有两种方式:
①用一个xib文件来描述UITableViewCell的内容。
②通过代码往UITableViewCell的contentView中添加子视图,在初始化方法(比如init、initWithStyle:reuseIdentifier:)中添加子控件,在layoutSubviews方法中分配子控件的位置和大小。
方法一:
1:首先计算需要显示在界面上cell的大小,然后显示相应的内容。当新出现一个cell的时候,去重用列队拿一个cell。然后去除上面显示的所有子视图(但是这样创建对象的消耗也会相应增加)。在重新创建对应位置的控件,进行赋值操作。
2:在初始化的时候,只需要创建对应的控件即可。然后在进行数据操作的时候设置相应控件的参数。
3:出现新cell的时候机会先调用显示,然后在调用高度。所以只要保证先获取对应位置cell的高度,然后在对各个控件进行赋值操作。
注意:每一个控件都要是全局的变量,这样才可以在该界面一直使用。
6)在表格视图界面点击一个按钮回到最开始的cell
- (void)scrollToRowAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated;//使用这个方法即可
[tableView scrollToRowAtIndexPath:[NSIndexPathindexPathForRow:0inSection:0]
atScrollPosition:UITableViewScrollPositionTop animated:YES];//就是这个效果点击
button 之后回到顶部
7):在UITableviewCell上知道自己点击了哪一个 button
-(void)buttonPressed:(id)sender { //button点击事件
UITableViewCell *clickedCell = (UITableViewCell *)[[sender superview] superview];
NSIndexPath *clickedButtonPath = [self.tableView indexPathForCell:clickedCell];
...
}
方法二:
- (void)buttonTappedAction:(id)sender {
CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:buttonPosition];
...
}
8) 删除重用的cell的所有子视图
从而得到一个没有特殊格式的cell,供其他cell重用。(可以很好的把对cell有过操作的效果全部去掉,然后拿过来重新使用,要保持之前的状态,只需要之前先存储好,在调用代理方法的时候获取数据显示即可)
if (cell ==
nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier];
}
else
{
//删除cell的所有子视图
while ([cell.contentView.subviews lastObject] !=nil)
{
[(UIView*)[cell.contentView.subviews lastObject] removeFromSuperview];
}
}
9)获取对应位置cell的方法.
NSIndexPath *cellIndexPath=[NSIndexPath
indexPathForRow:indexPath.row inSection:indexPath.section];
UITableViewCell *cell=[tableViewcellForRowAtIndexPath:cellIndexPath];
10)
设置tableViewCell间的分割线的颜色
[tableView setSeparatorColor:[UIColorredColor]];
改变UITableViewCell选中时背景色:
cell.selectedBackgroundView = [[UIView alloc] initWithFrame:cell.frame];
cell.selectedBackgroundView.backgroundColor = [UIColorredColor];
相关文章推荐
- IOS学习笔记18—UIImageView
- UGUI 事件响应之EventSystem
- UITableView启动后自动设置滚动的位置
- iOS开发-UI 从入门到精通(三)
- __builtin_popcount(n)
- IEnumerable和IQueryable区别、优缺点
- NGUI九宫格反向切割拉伸
- LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
- easyui-tabs图标(获取焦点时显示图标,失去焦点时隐藏图标)
- 设置UIView圆角 cornerRadius 圆角有性能问题,用贝塞尔曲线代替
- LeetCode || Permutation Sequence
- Swing-布局管理器应用--WIN7上计算器的UI实现
- Davinci内核镜像uImage的编译
- IOS 05 UIScrollView介绍 图片轮播器
- POJ 2785 4 Values whose Sum is 0(折半枚举)
- requirejs 基础
- IOS开发UI篇--一个支持图文混排的ActionSheet
- Kienct与Arduino学习笔记(2) 深度图像与现实世界的深度图的坐标
- 接收终端Request.InputStream阅读
- MYSQL启动后报:ERROR! The server quit without updating PID file错误的问题解决