准备工作:
创建一个工程
Model:
载有数据的 Person.plist 文件(里面包含了通讯录的所有内容,包括姓名 ,电话号码,头像等)
Person 类
把装有 头像图片的文件夹 拖入到工程中
-------------------------------------------------------------------------------------------------------------------------------
主要代码:
ContactView.h
#import <UIKit/UIKit.h>
@interface ContactView : UIView
@property(nonatomic,strong)UITableView *mainTableView;
@end
ContactView.m
#import "ContactView.h"
@implementation ContactView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self createMainTableView];
}
return self;
}
-(void)createMainTableView{
//UITableViewStyleGrouped 分组有头部和尾部
//UITableViewStylePlain 无分组,可加
self.mainTableView = [[UITableView alloc]initWithFrame:[UIScreen mainScreen].bounds style:UITableViewStylePlain];
[self addSubview:self.mainTableView];
}
@end
对应的控制器
ContactViewController.m
//
// ContactViewController.m
// UI10_lesson1
//
// Created by lanou3g on 15/11/4.
// Copyright (c) 2015年 lirui. All rights reserved.
//
#import "ContactViewController.h"
#import "ContactView.h"
#import "Person.h"
#import "DetailViewController.h"
@interface ContactViewController ()<UITableViewDataSource,UITableViewDelegate>
//创建根视图
@property(nonatomic,strong)ContactView *rootView;
//创建字典,存储联系人
@property(nonatomic,strong)NSMutableDictionary *contactDict;
//定义数组,专门用来存放分组名(A,B,C...)
@property(nonatomic,strong)NSMutableArray *groupNameArray;
@end
@implementation ContactViewController
//懒加载 字典
-(NSMutableDictionary *)contactDict{
if (_contactDict == nil) {
_contactDict = [NSMutableDictionary dictionary];
}
return _contactDict;
}
//懒加载 数组
-(NSMutableArray *)groupNameArray{
if (_groupNameArray == nil) {
_groupNameArray = [NSMutableArray array];
}
return _groupNameArray;
}
-(void)loadView{
self.rootView = [[ContactView alloc]initWithFrame:[UIScreen mainScreen].bounds];
self.view = self.rootView;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"通讯录";
//plist 文件路径
NSString *path = [[NSBundle mainBundle]pathForResource:@"Person" ofType:@"plist"];
//取出 plist 文件整体的内容
NSDictionary *sumDict = [NSDictionary dictionaryWithContentsOfFile:path];
//循环遍历 sumDict (相当于遍历分组名)
for (NSString *key in sumDict) {
//拿出分组所在的数组(存储的是一组联系人)
NSArray *valueArray = [sumDict objectForKey:key];
//把分组名存储起来(groupNameArray)
[self.groupNameArray addObject:key];
//创建可变数组,用来存储联系人模型
NSMutableArray *array = [NSMutableArray array];
//遍历 valueArray(遍历一个分组联系人)
for (NSDictionary *dict in valueArray) {
//创建对应的模型,并且使用 KVC 赋值
Person *p = [[Person alloc]init];
[p setValuesForKeysWithDictionary:dict];
//把模型存入对应的可变数组
[array addObject:p];
}
//把上面创建的 可变数组 存入 ContactDict;
[self.contactDict setObject:array forKey:key];
}
//给 groupNameArray 进行排序(仅限数组存的是 字符串)
[self.groupNameArray sortUsingSelector:@selector(compare:)];
//设置 mainTableView 的代理
self.rootView.mainTableView.dataSource = self;
self.rootView.mainTableView.delegate = self;
UIBarButtonItem *rightButton = [[UIBarButtonItem alloc]initWithTitle:@"编辑" style:UIBarButtonItemStylePlain target:self action:@selector(rightButtonDidClicked:)];
self.navigationItem.rightBarButtonItem = rightButton;
}
#pragma mark 导航栏右侧按钮的编辑事件
-(void)rightButtonDidClicked:(UIBarButtonItem *)sender {
if ([sender.title isEqualToString:@"编辑"]) {
//让 mainTableView 进入编辑状态
[self.rootView.mainTableView setEditing:YES animated:YES];
sender.title = @"完成";
} else {
// 结束编辑状态
[self.rootView.mainTableView setEditing:NO animated:YES];
sender.title = @"编辑";
}
}
#pragma mark 返回多少个分组
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return self.groupNameArray.count;
}
#pragma mark 每个分组返回多少行
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
//取出 key 值 (分组名)
NSString *key = self.groupNameArray[section];
NSArray *groupArray = self.contactDict[key];
return groupArray.count;
}
#pragma mark 每行显示的内容(cell 上面的内容)
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//cell 的重用机制
static NSString *cell_id = @"flag"; //(static 只创建一次)
//先到重用池里找可用的 cell (flag 标示符必须一样)
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cell_id];
//如果找不到,重新创建
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cell_id];
}
// cell 的下一级菜单指示
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
// 可以 自定义 : 添加到 cell.accessoryView
//赋值操作
NSString *key = self.groupNameArray[indexPath.section];
NSArray *valuesArray = self.contactDict[key];
Person *p = valuesArray[indexPath.row];
cell.textLabel.text = p.name;
cell.detailTextLabel.text = p.phoneNumber;
cell.imageView.image = [UIImage imageNamed:p.picture];
return cell;
}
#pragma mark 返回cell的高度
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 50.0f;
}
#pragma mark 设置分组头部的 title
//-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
//
// return self.groupNameArray[section];
//}
#pragma mark 自定义 tableView 分区头部
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView *headerView = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 30)];
UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"NavBar_64@2x.jpg"]];
imageView.frame = headerView.bounds;
//把图片添加到 headerView
[headerView addSubview:imageView];
UILabel *label = [[UILabel alloc]initWithFrame:headerView.bounds];
label.text = self.groupNameArray[section];
label.textAlignment = NSTextAlignmentCenter; //居中
[headerView addSubview:label];
return headerView;
}
#pragma mark 设置分区头部的高度
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 30.0f;
}
#pragma mark 以下是关于 tableView 设置尾部的方法(只是为了看看效果,太丑了,就注释了)
/* ------
#pragma mark 设置尾部的高度
-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
return 20;
}
#pragma mark 尾部的 title
-(NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
return @"玩完了";
}
#pragma mark 自定义尾部
-(UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
return nil;
}
------------------------- */
#pragma mark tableView 索引
-(NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return self.groupNameArray;
}
#pragma mark tableView cell 的点击方法
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//细节处理:取消 cell 的选中状态
[tableView deselectRowAtIndexPath:indexPath animated:YES];
//跳转到详情页面
DetailViewController *detailVC = [[DetailViewController alloc]init];
//通过属性传值过程
NSString *key = self.groupNameArray[indexPath.section];
NSArray *personArray = self.contactDict[key];
detailVC.receivePerson = personArray[indexPath.row];
[self.navigationController pushViewController:detailVC animated:YES];
}
//以下 3个方法 一起使用
#pragma mark 通知 tableView 哪些行可以进行编辑(添加和删除)
-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
#pragma mark 指定编辑的类型(删除还是添加)
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0) {
return UITableViewCellEditingStyleDelete;//删除
}else {
return UITableViewCellEditingStyleInsert;//添加
}
}
#pragma mark 提交编辑结果
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
//1.必须首先修改数据源
NSString *key = self.groupNameArray[indexPath.section];
NSMutableArray *mutableArray = self.contactDict[key];
//根据下标 删除数组里面对应的模型
[mutableArray removeObjectAtIndex:indexPath.row];
//如果 分组里面元素个数 小于1 (没有其他联系人了),需要删除整个分组
if (mutableArray.count < 1) {
[self.contactDict removeObjectForKey:key];
[self.groupNameArray removeObject:key];
}
//2.修改UI
// 方式① ---- reloadData 直接刷新数据
// [tableView reloadData];
//方式②
if (mutableArray.count < 1) {
//删除整个分组
NSIndexSet *deleteIndexSet = [NSIndexSet indexSetWithIndex:indexPath.section];
[tableView deleteSections:deleteIndexSet withRowAnimation:UITableViewRowAnimationAutomatic];
} else {
//删除某一行
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
} else {
//添加联系人
Person *insertPerson = [[Person alloc]init];
insertPerson.name = @"测试添加";
insertPerson.phoneNumber = @"13011777838";
//1.修改数据源
//分组名
NSString *key = self.groupNameArray[indexPath.section];
NSMutableArray *personArray = self.contactDict[key];
//给数组插入一个元素
[personArray insertObject:insertPerson atIndex:indexPath.row + 1];
//2.修改 UI
//方式①
// [tableView reloadData];
//方法②
//构造一个新的 indexPath
NSIndexPath *insertIndexPath = [NSIndexPath indexPathForRow:indexPath.row + 1 inSection:indexPath.section];
[tableView insertRowsAtIndexPaths:@[insertIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
}
#pragma mark 修改滑动删除时候的显示字样,默认是 Delete
-(NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath {
return @"删除";
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end
其中重点部分有:1. plist文件的解析过程
2.cell 的重用机制
设置代理后,代理方法的使用也要熟练掌握。
点击 导航栏 右侧的 编辑按钮
左滑进行删除