UI第十八节——UITableView
Posted 向日葵
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UI第十八节——UITableView相关的知识,希望对你有一定的参考价值。
在ios开发中UITableView可以说是使用最广泛的控件,我们平时使用的软件中到处都可以看到它的影子,基本大部分应用都有UITableView。当然它的广泛使用自然离不开它强大的功能,今天就针对UITableView重点展开讨论。
1.UITableView有两种风格:UITableViewStylePlain和UITableViewStyleGrouped。
一。如何选择grouped Or Plain
1.grouped的sectionHeader,sectionFooter的背景色默认跟tableview的背景色一样。plain反之
2.grouped的sectionHeader不会悬浮。plain反之。
3.plain会出现多余的分割线,grouped不会。
4.grouped某一行的上线边缘默认会有分割线。
5.优先使用grouped。
6.不管使用那种类型,不建议使用_tableView.sectionHeaderHeight =1; _tableView.sectionFooterHeight =50这种来定义sectionView高度,建议实现代理方法。因为有的时候grouped好像不起效果。
UITableViewStylePlain 类型时,
解决多余分割线问题,
UIView *v = [[UIView alloc] initWithFrame:CGRectMake(0,0,CGRectGetWidth(self.view.bounds),0)];
_tableView.tableFooterView = v;
解决默认sectionHeader sectionFooter颜色问题
- (void)tableView:(UITableView *)tableView willDisplayFooterView:(UIView *)view forSection:(NSInteger)section {
view.tintColor = [NWUtility colorWithHex:0xF0F0F0];
}
来两个图片对比一下
2.UITableView中每行数据都是一个UITableViewCell,在这个控件中为了显示更多的信息,
iOS已经在其内部设置好了多个子控件以供开发者使用。如果我们查看UITableViewCell的声明文件可以发现在内部有一个UIView控件
(contentView,作为其他元素的父控件)、两个UILable控件(textLabel、detailTextLabel)、一个UIImage控件(imageView),
分别用于容器、显示内容、详情和图片。使用效果类似于微信、QQ信息列表:
当然,这些子控件并不一定要全部使用,具体操作时可以通过UITableViewCellStyle进行设置,具体每个枚举表示的意思已经在代码中进行了注释:
typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
UITableViewCellStyleDefault, // 左侧显示textLabel(不显示detailTextLabel),imageView可选(显示在最左边)
UITableViewCellStyleValue1, // 左侧显示textLabel、右侧显示detailTextLabel(默认蓝色),imageView可选(显示在最左边)
UITableViewCellStyleValue2, // 左侧依次显示textLabel(默认蓝色)和detailTextLabel,imageView可选(显示在最左边)
UITableViewCellStyleSubtitle // 左上方显示textLabel,左下方显示detailTextLabel(默认灰色),imageView可选(显示在最左边)
};
由于iOS是遵循MVC模式设计的,很多操作都是通过代理和外界沟通的,但对于数据源控件除了代理还有一个数据源属性,
通过它和外界进行数据交互。 对于UITableView设置完dataSource后需要实现UITableViewDataSource协议,
在这个协议中定义了多种 数据操作方法,下面通过创建一个简单的联系人管理进行演示:
首先我们需要创建一个联系人模型KCContact
KCContact.h
//
// Contact.h
// UITableView
//
// Created by Kenshin Cui on 14-3-1.
// Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface KCContact : NSObject
#pragma mark 姓
@property (nonatomic,copy) NSString *firstName;
#pragma mark 名
@property (nonatomic,copy) NSString *lastName;
#pragma mark 手机号码
@property (nonatomic,copy) NSString *phoneNumber;
#pragma mark 带参数的构造函数
-(KCContact *)initWithFirstName:(NSString *)firstName andLastName:(NSString *)lastName andPhoneNumber:(NSString *)phoneNumber;
#pragma mark 取得姓名
-(NSString *)getName;
#pragma mark 带参数的静态对象初始化方法
+(KCContact *)initWithFirstName:(NSString *)firstName andLastName:(NSString *)lastName andPhoneNumber:(NSString *)phoneNumber;
@end
KCContact.m
//
// Contact.m
// UITableView
//
// Created by Kenshin Cui on 14-3-1.
// Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//
#import "KCContact.h"
@implementation KCContact
-(KCContact *)initWithFirstName:(NSString *)firstName andLastName:(NSString *)lastName andPhoneNumber:(NSString *)phoneNumber{
if(self=[super init]){
self.firstName=firstName;
self.lastName=lastName;
self.phoneNumber=phoneNumber;
}
return self;
}
-(NSString *)getName{
return [NSString stringWithFormat:@"%@ %@",_lastName,_firstName];
}
+(KCContact *)initWithFirstName:(NSString *)firstName andLastName:(NSString *)lastName andPhoneNumber:(NSString *)phoneNumber{
KCContact *contact1=[[KCContact alloc]initWithFirstName:firstName andLastName:lastName andPhoneNumber:phoneNumber];
return contact1;
}
@end
为了演示分组显示我们不妨将一组数据也抽象成模型KCContactGroup
KCContactGroup.h
//
// KCContactGroup.h
// UITableView
//
// Created by Kenshin Cui on 14-3-1.
// Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "KCContact.h"
@interface KCContactGroup : NSObject
#pragma mark 组名
@property (nonatomic,copy) NSString *name;
#pragma mark 分组描述
@property (nonatomic,copy) NSString *detail;
#pragma mark 联系人
@property (nonatomic,strong) NSMutableArray *contacts;
#pragma mark 带参数个构造函数
-(KCContactGroup *)initWithName:(NSString *)name andDetail:(NSString *)detail andContacts:(NSMutableArray *)contacts;
#pragma mark 静态初始化方法
+(KCContactGroup *)initWithName:(NSString *)name andDetail:(NSString *)detail andContacts:(NSMutableArray *)contacts;
@end
KCContactGroup.m
//
// KCContactGroup.m
// UITableView
//
// Created by Kenshin Cui on 14-3-1.
// Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//
#import "KCContactGroup.h"
@implementation KCContactGroup
-(KCContactGroup *)initWithName:(NSString *)name andDetail:(NSString *)detail andContacts:(NSMutableArray *)contacts{
if (self=[super init]) {
self.name=name;
self.detail=detail;
self.contacts=contacts;
}
return self;
}
+(KCContactGroup *)initWithName:(NSString *)name andDetail:(NSString *)detail andContacts:(NSMutableArray *)contacts{
KCContactGroup *group1=[[KCContactGroup alloc]initWithName:name andDetail:detail andContacts:contacts];
return group1;
}
@end
然后在viewDidLoad方法中创建一些模拟数据同时实现数据源协议方法:
KCMainViewController.m
//
// KCMainViewController.m
// UITableView
//
// Created by Kenshin Cui on 14-3-1.
// Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//
#import "KCMainViewController.h"
#import "KCContact.h"
#import "KCContactGroup.h"
@interface KCMainViewController ()<UITableViewDataSource>{
UITableView *_tableView;
NSMutableArray *_contacts;//联系人模型
}
@end
@implementation KCMainViewController
- (void)viewDidLoad {
[super viewDidLoad];
//初始化数据
[self initData];
//创建一个分组样式的UITableView
_tableView=[[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
//设置数据源,注意必须实现对应的UITableViewDataSource协议
_tableView.dataSource=self;
[self.view addSubview:_tableView];
}
#pragma mark 加载数据
-(void)initData{
_contacts=[[NSMutableArray alloc]init];
KCContact *contact1=[KCContact initWithFirstName:@"Cui" andLastName:@"Kenshin" andPhoneNumber:@"18500131234"];
KCContact *contact2=[KCContact initWithFirstName:@"Cui" andLastName:@"Tom" andPhoneNumber:@"18500131237"];
KCContactGroup *group1=[KCContactGroup initWithName:@"C" andDetail:@"With names beginning with C"
andContacts:[NSMutableArray arrayWithObjects:contact1,contact2, nil]];
[_contacts addObject:group1];
KCContact *contact3=[KCContact initWithFirstName:@"Lee" andLastName:@"Terry" andPhoneNumber:@"18500131238"];
KCContact *contact4=[KCContact initWithFirstName:@"Lee" andLastName:@"Jack" andPhoneNumber:@"18500131239"];
KCContact *contact5=[KCContact initWithFirstName:@"Lee" andLastName:@"Rose" andPhoneNumber:@"18500131240"];
KCContactGroup *group2=[KCContactGroup initWithName:@"L" andDetail:@"With names beginning with L"
andContacts:[NSMutableArray arrayWithObjects:contact3,contact4,contact5, nil]];
[_contacts addObject:group2];
KCContact *contact6=[KCContact initWithFirstName:@"Sun" andLastName:@"Kaoru" andPhoneNumber:@"18500131235"];
KCContact *contact7=[KCContact initWithFirstName:@"Sun" andLastName:@"Rosa" andPhoneNumber:@"18500131236"];
KCContactGroup *group3=[KCContactGroup initWithName:@"S" andDetail:@"With names beginning with S"
andContacts:[NSMutableArray arrayWithObjects:contact6,contact7, nil]];
[_contacts addObject:group3];
KCContact *contact8=[KCContact initWithFirstName:@"Wang" andLastName:@"Stephone" andPhoneNumber:@"18500131241"];
KCContact *contact9=[KCContact initWithFirstName:@"Wang" andLastName:@"Lucy" andPhoneNumber:@"18500131242"];
KCContact *contact10=[KCContact initWithFirstName:@"Wang" andLastName:@"Lily" andPhoneNumber:@"18500131243"];
KCContact *contact11=[KCContact initWithFirstName:@"Wang" andLastName:@"Emily" andPhoneNumber:@"18500131244"];
KCContact *contact12=[KCContact initWithFirstName:@"Wang" andLastName:@"Andy" andPhoneNumber:@"18500131245"];
KCContactGroup *group4=[KCContactGroup initWithName:@"W" andDetail:@"With names beginning with W"
andContacts:[NSMutableArray arrayWithObjects:contact8,contact9,contact10,contact11,contact12, nil]];
[_contacts addObject:group4];
KCContact *contact13=[KCContact initWithFirstName:@"Zhang" andLastName:@"Joy" andPhoneNumber:@"18500131246"];
KCContact *contact14=[KCContact initWithFirstName:@"Zhang" andLastName:@"Vivan" andPhoneNumber:@"18500131247"];
KCContact *contact15=[KCContact initWithFirstName:@"Zhang" andLastName:@"Joyse" andPhoneNumber:@"18500131248"];
KCContactGroup *group5=[KCContactGroup initWithName:@"Z" andDetail:@"With names beginning with Z"
andContacts:[NSMutableArray arrayWithObjects:contact13,contact14,contact15, nil]];
[_contacts addObject:group5];
}
#pragma mark - 数据源方法
#pragma mark 返回分组数
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
NSLog(@"计算分组数");
return _contacts.count;
}
#pragma mark 返回每组行数
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
NSLog(@"计算每组(组%i)行数",section);
KCContactGroup *group1=_contacts[section];
return group1.contacts.count;
}
#pragma mark返回每行的单元格
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
//NSIndexPath是一个结构体,记录了组和行信息
NSLog(@"生成单元格(组:%i,行%i)",indexPath.section,indexPath.row);
KCContactGroup *group=_contacts[indexPath.section];
KCContact *contact=group.contacts[indexPath.row];
UITableViewCell *cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
cell.textLabel.text=[contact getName];
cell.detailTextLabel.text=contact.phoneNumber;
return cell;
}
#pragma mark 返回每组头标题名称
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
NSLog(@"生成组(组%i)名称",section);
KCContactGroup *group=_contacts[section];
return group.name;
}
#pragma mark 返回每组尾部说明
-(NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section{
NSLog(@"生成尾部(组%i)详情",section);
KCContactGroup *group=_contacts[section];
return group.detail;
}
@end
运行可以看到如下效果:
大家在使用iPhone通讯录时会发现右侧可以按字母检索,使用起来很方便,其实这个功能使用UITableView实现很简单,
只要实现数据源协议的一个方法,构建一个分组标题的数组即可实现。数组元素的内容和组标题内容未必完全一致,
UITableView是按照数组元素的索引和每组数据索引顺序来定位的而不是按内容查找。
#pragma mark 返回每组标题索引
-(NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView{
NSLog(@"生成组索引");
NSMutableArray *indexs=[[NSMutableArray alloc]init];
for(KCContactGroup *group in _contacts){
[indexs addObject:group.name];
}
return indexs;
}
效果如下:
需要注意的是上面几个重点方法的执行顺序,请看下图:
值得指出的是生成单元格的方法并不是一次全部调用,而是只会生产当前显示在界面上的单元格,当用户滚动操作时再显示其他单元格
对于开发中,经常要添加头部视图,我们可以增加
_tableView.tableHeaderView= [self getHeader];
_tableView.tableFooterView=[self getFooter];
#pragma mrak ==头部视图==
-(UIView *)getHeader
{
UIView *view=[[UIView alloc]initWithFrame:CGRectMake(0, 0, Screen_width, 100)];
view.backgroundColor=[UIColor redColor];
return view;
}
-(UIView *)getFooter
{
UIView *view=[[UIView alloc]initWithFrame:CGRectMake(0, 0, Screen_width, 100)];
view.backgroundColor=[UIColor grayColor];
return view;
}
截图效果如下:
如果还要增加头部视图:可以加上如下代码:
_tableView.contentInset = UIEdgeInsetsMake(44, 0, 0, 0);
_tableView.scrollIndicatorInsets = UIEdgeInsetsMake(44, 0, 0, 0);
效果如下:
代理
上面我们已经看到通讯录的简单实现,但是我们发现单元格高度、分组标题高度以及尾部说明的高度都需要调整,
此时就需要使用代理方法。UITableView代理方法有很多,例如监听单元格显示周期、监听单元格选择编辑操作、设置是否高亮显示单元格、设置行高等。
1.设置行高
#pragma mark - 代理方法
#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;
}
2.监听点击
在iOS中点击某联系个人就可以呼叫这个联系人,这时就需要监听点击操作,这里就不演示呼叫联系人操作了,我们演示一下修改人员信息的操作。
KCMainViewContrller.m
//
// KCMainViewController.m
// UITableView
//
// Created by Kenshin Cui on 14-3-1.
// Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//
#import "KCMainViewController.h"
#import "KCContact.h"
#import "KCContactGroup.h"
@interface KCMainViewController ()<UITableViewDataSource,UITableViewDelegate,UIAlertViewDelegate>{
UITableView *_tableView;
NSMutableArray *_contacts;//联系人模型
NSIndexPath *_selectedIndexPath;//当前选中的组和行
}
@end
@implementation KCMainViewController
- (void)viewDidLoad {
[super viewDidLoad];
//初始化数据
[self initData];
//创建一个分组样式的UITableView
_tableView=[[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
//设置数据源,注意必须实现对应的UITableViewDataSource协议
_tableView.dataSource=self;
//设置代理
_tableView.delegate=self;
[self.view addSubview:_tableView];
}
#pragma mark 加载数据
-(void)initData{
_contacts=[[NSMutableArray alloc]init];
KCContact *contact1=[KCContact initWithFirstName:@"Cui" andLastName:@"Kenshin" andPhoneNumber:@"18500131234"];
KCContact *contact2=[KCContact initWithFirstName:@"Cui" andLastName:@"Tom" andPhoneNumber:@"18500131237"];
KCContactGroup *group1=[KCContactGroup initWithName:@"C" andDetail:@"With names beginning with C"
andContacts:[NSMutableArray arrayWithObjects:contact1,contact2, nil]];
[_contacts addObject:group1];
KCContact *contact3=[KCContact initWithFirstName:@"Lee" andLastName:@"Terry" andPhoneNumber:@"18500131238"];
KCContact *contact4=[KCContact initWithFirstName:@"Lee" andLastName:@"Jack" andPhoneNumber:@"18500131239"];
KCContact *contact5=[KCContact initWithFirstName:@"Lee" andLastName:@"Rose" andPhoneNumber:@"18500131240"];
KCContactGroup *group2=[KCContactGroup initWithName:@"L" andDetail:@"With names beginning with L"
andContacts:[NSMutableArray arrayWithObjects:contact3,contact4,contact5, nil]];
[_contacts addObject:group2];
KCContact *contact6=[KCContact initWithFirstName:@"Sun" andLastName:@"Kaoru" andPhoneNumber:@"18500131235"];
KCContact *contact7=[KCContact initWithFirstName:@"Sun" andLastName:@"Rosa" andPhoneNumber:@"18500131236"];
KCContactGroup *group3=[KCContactGroup initWithName:@"S" andDetail:@"With names beginning with S"
andContacts:[NSMutableArray arrayWithObjects:contact6,contact7, nil]];
[_contacts addObject:group3];
KCContact *contact8=[KCContact initWithFirstName:@"Wang" andLastName:@"Stephone" andPhoneNumber:@"18500131241"];
KCContact *contact9=[KCContact initWithFirstName:@"Wang" andLastName:@"Lucy" andPhoneNumber:@"18500131242"];
KCContact *contact10=[KCContact initWithFirstName:@"Wang" andLastName:@"Lily" andPhoneNumber:@"18500131243"];
KCContact *contact11=[KCContact initWithFirstName:@"Wang" andLastName:@"Emily" andPhoneNumber:@"18500131244"];
KCContact *contact12=[KCContact initWithFirstName:@"Wang" andLastName:@"Andy" andPhoneNumber:@"18500131245"];
KCContactGroup *group4=[KCContactGroup initWithName:@"W" andDetail:@"With names beginning with W"
andContacts:[NSMutableArray arrayWithObjects:contact8,contact9,contact10,contact11,contact12, nil]];
[_contacts addObject:group4];
KCContact *contact13=[KCContact initWithFirstName:@"Zhang" andLastName:@"Joy" andPhoneNumber:@"18500131246"];
KCContact *contact14=[KCContact initWithFirstName:@"Zhang" andLastName:@"Vivan" andPhoneNumber:@"18500131247"];
KCContact *contact15=[KCContact initWithFirstName:@"Zhang" andLastName:@"Joyse" andPhoneNumber:@"18500131248"];
KCContactGroup *group5=[KCContactGroup initWithName:@"Z" andDetail:@"With names beginning with Z"
andContacts:[NSMutableArray arrayWithObjects:contact13,contact14,contact15, nil]];
[_contacts addObject:group5];
}
#pragma mark - 数据源方法
#pragma mark 返回分组数
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
NSLog(@"计算分组数");
return _contacts.count;
}
#pragma mark 返回每组行数
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
NSLog(@"计算每组(组%i)行数",section);
KCContactGroup *group1=_contacts[section];
return group1.contacts.count;
}
#pragma mark返回每行的单元格
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
//NSIndexPath是一个对象,记录了组和行信息
NSLog(@"生成单元格(组:%i,行%i)",indexPath.section,indexPath.row);
KCContactGroup *group=_contacts[indexPath.section];
KCContact *contact=group.contacts[indexPath.row];
UITableViewCell *cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:nil];
cell.textLabel.text=[contact getName];
cell.detailTextLabel.text=contact.phoneNumber;
return cell;
}
#pragma mark 返回每组头标题名称
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
NSLog(@"生成组(组%i)名称",section);
KCContactGroup *group=_contacts[section];
return group.name;
}
#pragma mark 返回每组尾部说明
-(NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section{
NSLog(@"生成尾部(组%i)详情",section);
KCContactGroup *group=_contacts[section];
return group.detail;
}
#pragma mark 返回每组标题索引
-(NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView{
NSLog(@"生成组索引");
NSMutableArray *indexs=[[NSMutableArray alloc]init];
for(KCContactGroup *group in _contacts){
[indexs addObject:group.name];
}
return indexs;
}
#pragma mark - 代理方法
#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;
}
#pragma mark 点击行
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
_selectedIndexPath=indexPath;
KCContactGroup *group=_contacts[indexPath.section];
KCContact *contact=group.contacts[indexPath.row];
//创建弹出窗口
UIAlertView *alert=[[UIAlertView alloc]initWithTitle:@"System Info" message:[contact getName] delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK", nil];
alert.alertViewStyle=UIAlertViewStylePlainTextInput; //设置窗口内容样式
UITextField *textField= [alert textFieldAtIndex:0]; //取得文本框
textField.text=contact.phoneNumber; //设置文本框内容
[alert show]; //显示窗口
}
#pragma mark 窗口的代理方法,用户保存数据
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
//当点击了第二个按钮(OK)
if (buttonIndex==1) {
UITextField *textField= [alertView textFieldAtIndex:0];
//修改模型数据
KCContactGroup *group=_contacts[_selectedIndexPath.section];
KCContact *contact=group.contacts[_selectedIndexPath.row];
contact.phoneNumber=textField.text;
//刷新表格
[_tableView reloadData];
}
}
#pragma mark 重写状态样式方法
-(UIStatusBarStyle)preferredStatusBarStyle{
return UIStatusBarStyleLightContent;
}
@end
在上面的代码中我们通过修改模型来改变UI显示,这种方式是经典的MVC应用,在后面的代码中会经常看到。
当然UI的刷新使用了UITableView的reloadData方法,该方法会重新调用数据源方法,包括计算分组、
计算每个分组的行数,生成单元格等刷新整个UITableView。当然这种方式在实际开发中是不可取的,
我们不可能因为修改了一个人的信息就刷新整个UITableViewView,此时我们需要采用局部刷新。
局部刷新使用起来很简单,只需要调用UITableView的另外一个方法:
#pragma mark 窗口的代理方法,用户保存数据
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
//当点击了第二个按钮(OK)
if (buttonIndex==1) {
UITextField *textField= [alertView textFieldAtIndex:0];
//修改模型数据
KCContactGroup *group=_contacts[_selectedIndexPath.section];
KCContact *contact=group.contacts[_selectedIndexPath.row];
contact.phoneNumber=textField.text;
//刷新表格
NSArray *indexPaths=@[_selectedIndexPath];//需要局部刷新的单元格的组、行
[_tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationLeft];//后面的参数代表更新时的动画
}
}
性能优化
前面已经说过UITableView中的单元格cell是在显示到用户可视区域后创建的,那么如果用户往下滚
动就会继续创建显示在屏幕上的单元格,如果用户向上滚动返回到查看过的内容时同样会重新创建之
前已经创建过的单元格。如此一来即使UITableView的内容不是太多,如果用户反复的上下滚动,内
存也会瞬间飙升,更何况很多时候UITableView的内容是很多的(例如微博展示列表,基本向下滚动是没有底限的)。
前面一节中我们曾经提到过如何优化UIScrollView,当时就是利用有限的UIImageView动态切换其
内容来尽可能减少资源占用。同样的,在UITableView中也可以采用类似的方式,只是这时我们不是
在滚动到指定位置后更改滚动的位置而是要将当前没有显示的Cell重新显示在将要显示的Cell的位置然
后更新其内容。原因就是UITableView中的Cell结构布局可能是不同的,通过重新定位是不可取的,而
是需要重用已经不再界面显示的已创建过的Cell。
当然,听起来这么做比较复杂,其实实现起来很简单,因为UITableView已经为我们实现了这种机制。
在UITableView内部有一个缓存池,初始化时使用initWithStyle:(UITableViewCellStyle) reuseIdentifier:(NSString *)
方法指定一个可重用标识,就可以将这个cell放到缓存池。然后在使用时使用指定的标识去缓存池中取得对应的cell然后修改cell内容即可。
#pragma mark返回每行的单元格
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
//NSIndexPath是一个对象,记录了组和行信息
NSLog(@"生成单元格(组:%i,行%i)",indexPath.section,indexPath.row);
KCContactGroup *group=_contacts[indexPath.section];
KCContact *contact=group.contacts[indexPath.row];
//由于此方法调用十分频繁,cell的标示声明成静态变量有利于性能优化
static NSString *cellIdentifier=@"UITableViewCellIdentifierKey1";
//首先根据标识去缓存池取
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
//如果缓存池没有到则重新创建并放到缓存池中
if(!cell){
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier];
}
cell.textLabel.text=[contact getName];
cell.detailTextLabel.text=contact.phoneNumber;
NSLog(@"cell:%@",cell);
return cell;
}
上面的代码中已经打印了cell的地址,如果大家运行测试上下滚动UITableView会发现滚动时创建的cell地址是初始化时已经创建的。
这里再次给大家强调两点:
- -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)
- 方法调用很频繁,无论是初始化、上下滚动、刷新都会调用此方法,所有在这里执行的操作一定要注意性能;
- 可重用标识可以有多个,如果在UITableView中有多类结构不同的Cell,可以通过这个标识进行缓存和重新;
UITableViewCell
1.自带的UITableViewCell
UITableViewCell是构建一个UITableView的基础,在UITableViewCell内部有一个UIView控件作为其他内容的容器,
它上面有一个UIImageView和两个UILabel,通过UITableViewCellStyle属性可以对其样式进行控制。其结构如下:
有时候我们会发现很多UITableViewCell右侧可以显示不同的图标,在iOS中称之为访问器,点击可以触发不同的事件,例如设置功能:
要设置这些图标只需要设置UITableViewCell的accesoryType属性,这是一个枚举类型具体含义如下:
typedef NS_ENUM(NSInteger, UITableViewCellAccessoryType) {
UITableViewCellAccessoryNone, // 不显示任何图标
UITableViewCellAccessoryDisclosureIndicator, // 跳转指示图标
UITableViewCellAccessoryDetailDisclosureButton, // 内容详情图标和跳转指示图标
UITableViewCellAccessoryCheckmark, // 勾选图标
UITableViewCellAccessoryDetailButton NS_ENUM_AVAILABLE_IOS(7_0) // 内容详情图标
};
例如在最近通话中我们通常设置为详情图标,点击可以查看联系人详情:
很明显iOS设置中第一个accessoryType不在枚举之列,右侧的访问器类型是UISwitch控件,
那么如何显示自定义的访问器呢?其实只要设置UITableViewCell的accessoryView即可,
它支持任何UIView控件。假设我们在通讯录每组第一行放一个UISwitch,同时切换时可以输出对应信息:
//
// KCMainViewController.m
// UITableView
//
// Created by Kenshin Cui on 14-3-1.
// Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//
#import "KCMainViewController.h"
#import "KCContact.h"
#import "KCContactGroup.h"
@interface KCMainViewController ()<UITableViewDataSource,UITableViewDelegate,UIAlertViewDelegate>{
UITableView *_tableView;
NSMutableArray *_contacts;//联系人模型
NSIndexPath *_selectedIndexPath;//当前选中的组和行
}
@end
@implementation KCMainViewController
- (void)viewDidLoad {
[super viewDidLoad];
//初始化数据
[self initData];
//创建一个分组样式的UITableView
_tableView=[[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
//设置数据源,注意必须实现对应的UITableViewDataSource协议
_tableView.dataSource=self;
//设置代理
_tableView.delegate=self;
[self.view addSubview:_tableView];
}
#pragma mark 加载数据
-(void)initData{
_contacts=[[NSMutableArray alloc]init];
KCContact *contact1=[KCContact initWithFirstName:@"Cui" andLastName:@"Kenshin" andPhoneNumber:@"18500131234"];
KCContact *contact2=[KCContact initWithFirstName:@"Cui" andLastName:@"Tom" andPhoneNumber:@"18500131237"];
KCContactGroup *group1=[KCContactGroup initWithName:@"C" andDetail:@"With names beginning with C"
andContacts:[NSMutableArray arrayWithObjects:contact1,contact2, nil]];
[_contacts addObject:group1];
KCContact *contact3=[KCContact initWithFirstName:@"Lee" andLastName:@第十八节:上下文管理协议