Welcome

首页 / 移动开发 / IOS / 如何自定义iOS通讯录

苹果给用户提供了自己的通讯录,但是根据业务的需求,需要自定义通讯录,我们就需要根据业务需求来自定义。
首先我们需要知道苹果的提供的一些Foundation、UIKit框架,了解其中的一些特性,可以打开手机查看苹果系统提供的原生的通讯录,可以看到:

1.搜索框
2.右侧搜索条
3.联系人分组
4.添加联系人
5.获取联系人头像及联系方式

根据需求,可以总结出自定义通讯录需要做的一些功能,一项大的功能可以差分成一些小的功能,然后一个一个实现,将复杂的问题差分成小问题解决。

1.自定义搜索框
2.获取首字母
3.权限判断
4.排序
5.自定义搜索
6.自定义联系人界面
(考虑多值的情况,获取通讯录头像)

简答介绍下排序:

IOS项目中会用到对通讯录的联系人或是会员按姓名为关键字排序,因为NSArray并不直接支持对汉字的排序,这就要通过将汉字转换成拼音完成按A~Z的排序,这看起来是个头疼的问题,因为牵扯到汉字转为拼音,获取汉字的首字的首字母,如将“王”变成“W”。

函数原理是:我们知道,在Objective C语言中,字符串是以unicode进行编码的。在unicode字符集中,汉字的编码范围为4E00 到 9FA5 之间(即从第19968开始的20902个字符是中文简体字符)。我们把这些字符的拼音首字母按照顺序都存放在一个char数组中。当我们查找一个汉字的拼音首字母时,只需把这个汉字的unicode码(即char强制转换为int)减去19968,然后用这个数字作为索引去找char数组中存放的字母即可。
给出项目的源码,注释很清楚。代码如:
RYAddressBook.h

#import <Foundation/Foundation.h> #import "RYPersonInfo.h"typedef void (^AddressBookBlock) (NSArray *personInfos);@interface RYAddressBook : NSObject/*** 将数字转化为字母 0~26 1~25=a~z 26=#*/ NSString* SpellFromIndex(int index);/*** 获取索引*/ int Index(NSString *firstSpell); /*** 获取用户所有通讯录信息** @return 所有通讯录数据信息数组*/ + (void)getPersonInfo:(AddressBookBlock)addressBookBlock;/*** 根据关键字匹配所有用户信息** @param keyWord 匹配关键字** @return 匹配到的通讯录数据信息数组*/ + (void)searchPersonInfo:(NSString *)keyWord addressBookBlock:(AddressBookBlock)addressBookBlock;/*** 根据姓名进行数组的重排序** @param personInfos 获取的通讯录数据信息数组*/ + (NSArray *)sortPersonInfos:(NSArray *)personInfos;@end 
RYAddressBook.m

#import "RYAddressBook.h"@interface RYAddressBook ()@property (nonatomic, copy) AddressBookBlock addressBookBlock;@end@implementation RYAddressBookNSString* SpellFromIndex(int index) {if (index == 26)return @"#";elsereturn [NSString stringWithFormat:@"%c", [@"A" characterAtIndex:0]+index]; }int Index(NSString *firstSpell) {int i = [firstSpell characterAtIndex:0] - [@"a" characterAtIndex:0]; if ([firstSpell isEqualToString:@"#"] || i < 0 || i > 26) {return 26;} return [firstSpell characterAtIndex:0] - [@"a" characterAtIndex:0]; }/*** 获取用户所有通讯录信息*/ + (void)getPersonInfo:(AddressBookBlock)addressBookBlock {[[self alloc] getPersonInfo:addressBookBlock]; }/*** 根据关键字匹配所有用户信息*/ + (void)searchPersonInfo:(NSString *)keyWord addressBookBlock:(AddressBookBlock)addressBookBlock {[[self alloc] searchPersonInfo:keyWord addressBookBlock:addressBookBlock]; }/*** 根据姓名进行数组的重排序*/ + (NSArray *)sortPersonInfos:(NSArray *)personInfos {return [[self alloc] sortPersonInfos:personInfos]; }- (void)getPersonInfo:(AddressBookBlock)addressBookBlock {self.addressBookBlock = addressBookBlock;[self searchPersonInfo:@""]; }- (void)searchPersonInfo:(NSString *)keyWord addressBookBlock:(AddressBookBlock)addressBookBlock {self.addressBookBlock = addressBookBlock;[self searchPersonInfo:keyWord]; }- (NSArray *)sortPersonInfos:(NSArray *)personInfos {if (![personInfos isKindOfClass:[NSArray class]]) {return nil;} NSMutableArray *arr = [NSMutableArray array]; for (int i = 0; i < 27; i++) {[arr addObject:[NSMutableArray array]];} for (NSObject *obj in personInfos) {if (![obj isKindOfClass:[RYPersonInfo class]]) { continue;}RYPersonInfo *personInfo = (RYPersonInfo *)obj;NSMutableArray *subArr = [arr objectAtIndex:Index(personInfo.firstSpell)];[subArr addObject:personInfo];} return arr; }/*** 根据关键字查询通讯录信息*/ - (void)searchPersonInfo:(NSString *)keyWord {CFErrorRef error = NULL;ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error); // 开始查询通讯录ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {if (granted) { [self filterContentForSearchText:keyWord];}}); }/*** 开始匹配通讯录信息*/ - (void)filterContentForSearchText:(NSString*)searchText {//如果没有授权则退出if (ABAddressBookGetAuthorizationStatus() != kABAuthorizationStatusAuthorized) {return;} NSArray *blockArray = [NSArray array]; CFErrorRef error = NULL;ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error); if([searchText length]==0){//查询所有blockArray = (__bridge NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook);} else {//条件查询CFStringRef cfSearchText = (CFStringRef)CFBridgingRetain(searchText);blockArray = CFBridgingRelease(ABAddressBookCopyPeopleWithName(addressBook, cfSearchText));CFRelease(cfSearchText);} // 类型转换blockArray = transformElements(blockArray); // 返回BlockArrayself.addressBookBlock(blockArray); }/*** 将所有元素转化为JXPersonInfo类型数组*/ NSArray* transformElements(NSArray* arr) {NSMutableArray *rtnArray = [NSMutableArray array];for (int i = 0; i < arr.count; i++) {ABRecordRef recordRef = CFBridgingRetain([arr objectAtIndex:i]);RYPersonInfo *personInfo = [RYPersonInfo personInfoWithABRecordRef:recordRef];[rtnArray addObject:personInfo];}return rtnArray; } @end 
RYPersonInfo.h

#import <Foundation/Foundation.h> #import <AddressBook/AddressBook.h>@interface RYPersonInfo : NSObject/*** 单值信息*/ #define PROPERTY_STR_READONLY(name) @property (nonatomic, copy) NSString *name; // 姓 PROPERTY_STR_READONLY(firstName) // 名 PROPERTY_STR_READONLY(lastName) // 中间名 PROPERTY_STR_READONLY(middlename) // 全名 PROPERTY_STR_READONLY(fullName) // 搜索索引 PROPERTY_STR_READONLY(firstSpell) // 前缀 PROPERTY_STR_READONLY(prefix) // 后缀 PROPERTY_STR_READONLY(suffix) // 昵称 PROPERTY_STR_READONLY(nickname) // 姓_音标 PROPERTY_STR_READONLY(firstnamePhonetic) // 名_音标 PROPERTY_STR_READONLY(lastnamePhonetic) // 中间名_音标 PROPERTY_STR_READONLY(middlenamePhonetic) // 公司 PROPERTY_STR_READONLY(organization) // 工作 PROPERTY_STR_READONLY(jobtitle) // 部门 PROPERTY_STR_READONLY(department) // 生日 PROPERTY_STR_READONLY(birthday) // 备忘录 PROPERTY_STR_READONLY(note) // 第一次创建用户信息的时间 PROPERTY_STR_READONLY(firstknow) // 最后一次更改用户信息的时间 PROPERTY_STR_READONLY(lastknow) // 名片类型(company/person) PROPERTY_STR_READONLY(kind)// 多值信息 #define PROPERTY_ARR_READONLY(name) @property (nonatomic, strong) NSArray *name; // 邮箱 PROPERTY_ARR_READONLY(email) // 地址 PROPERTY_ARR_READONLY(address) // 日期 PROPERTY_ARR_READONLY(dates) // iMessage PROPERTY_ARR_READONLY(iMessage) // 电话号码 PROPERTY_ARR_READONLY(phone) // URL链接 PROPERTY_ARR_READONLY(url)#define PROPERTY_IMG_READONLY(name) @property (nonatomic, strong) UIImage *name; // 图片 //PROPERTY_IMG_READONLY(image) /*** 初始化方法** @param ref 联系人属性** @return 实例对象*/ - (id)initWithABRecordRef:(ABRecordRef)ref;/*** 初始化类方法** @param ref 联系人属性** @return 实例对象*/ + (id)personInfoWithABRecordRef:(ABRecordRef)ref;@end 
RYPersonInfo.m

#import "RYPersonInfo.h"#define nullStrToEmpty(str)  [str rangeOfString:@"null"].location==0? @"" : str/*** 单值信息*/ #define GET_PROPERTY_METHOD(property, property_key)  - (NSString *)property { return (NSString *)CFBridgingRelease(ABRecordCopyValue(_recordRef, property_key)); }/*** 多值信息*/ #define DICT_ADD_STR_FOR_KEY(dict, str, key)  if (str) { [dict setObject:str forKey:key]; } #define GET_PROPERTY_SIGLE_VALUE_METHOD(property, property_key) - (NSArray *)property { NSMutableArray *rtnArray = [NSMutableArray array];  ABMultiValueRef ref = ABRecordCopyValue(_recordRef, property_key); long count = ABMultiValueGetCount(ref); for (int i = 0; i < count; i++) { NSString* label = (__bridge NSString*)ABAddressBookCopyLocalizedLabel(ABMultiValueCopyLabelAtIndex(ref, i)); NSString* content = (__bridge NSString*)ABMultiValueCopyValueAtIndex(ref, i); NSMutableDictionary *dict = [NSMutableDictionary dictionary]; DICT_ADD_STR_FOR_KEY(dict, content, label);  [rtnArray addObject:dict]; } return rtnArray; }@interface RYPersonInfo ()@property (nonatomic , assign)ABRecordRef recordRef;@end@implementation RYPersonInfo- (id)initWithABRecordRef:(ABRecordRef)ref {if (self = [super init]) {_recordRef = ref;}return self; }+ (id)personInfoWithABRecordRef:(ABRecordRef)ref {return [[[self class] alloc] initWithABRecordRef:ref]; }GET_PROPERTY_METHOD( firstName , kABPersonFirstNameProperty); GET_PROPERTY_METHOD( lastName , kABPersonLastNameProperty); GET_PROPERTY_METHOD( middlename , kABPersonMiddleNameProperty); GET_PROPERTY_METHOD( prefix , kABPersonPrefixProperty); GET_PROPERTY_METHOD( suffix , kABPersonSuffixProperty); GET_PROPERTY_METHOD( nickname , kABPersonNicknameProperty); GET_PROPERTY_METHOD( organization , kABPersonOrganizationProperty); GET_PROPERTY_METHOD( jobtitle , kABPersonJobTitleProperty); GET_PROPERTY_METHOD( department , kABPersonDepartmentProperty); GET_PROPERTY_METHOD( birthday , kABPersonBirthdayProperty); GET_PROPERTY_METHOD( note, kABPersonNoteProperty); GET_PROPERTY_METHOD( firstknow , kABPersonCreationDateProperty); GET_PROPERTY_METHOD( lastknow , kABPersonModificationDateProperty); GET_PROPERTY_METHOD( firstnamePhonetic , kABPersonFirstNamePhoneticProperty); GET_PROPERTY_METHOD( lastnamePhonetic , kABPersonLastNamePhoneticProperty); GET_PROPERTY_METHOD( middlenamePhonetic, kABPersonMiddleNamePhoneticProperty);GET_PROPERTY_SIGLE_VALUE_METHOD(email, kABPersonEmailProperty) GET_PROPERTY_SIGLE_VALUE_METHOD(dates, kABPersonDateProperty) GET_PROPERTY_SIGLE_VALUE_METHOD(url , kABPersonURLProperty) GET_PROPERTY_SIGLE_VALUE_METHOD(phone, kABPersonPhoneProperty)- (NSString *)kind {NSString *rtnStr = nil;CFNumberRef recordType = ABRecordCopyValue(_recordRef, kABPersonKindProperty);if (recordType == kABPersonKindOrganization) {rtnStr = @"company";} else {rtnStr = @"person";}return rtnStr; }- (NSArray *)iMessage {NSMutableArray *rtnArray = [NSMutableArray array]; ABMultiValueRef instantMessage = ABRecordCopyValue(_recordRef, kABPersonInstantMessageProperty);for (int i = 1; i < ABMultiValueGetCount(instantMessage); i++){NSString* label = (__bridge NSString*)ABMultiValueCopyLabelAtIndex(instantMessage, i);NSDictionary* content =(__bridge NSDictionary*) ABMultiValueCopyValueAtIndex(instantMessage, i);NSMutableDictionary *imessageInfoDict = [NSMutableDictionary dictionary];NSString* username = [content valueForKey:(NSString *)kABPersonInstantMessageUsernameKey];NSString* service = [content valueForKey:(NSString *)kABPersonInstantMessageServiceKey];DICT_ADD_STR_FOR_KEY(imessageInfoDict, username, @"username");DICT_ADD_STR_FOR_KEY(imessageInfoDict, service, @"service");NSDictionary *imessageDict = @{label: imessageInfoDict};[rtnArray addObject:imessageDict];}return rtnArray; }-(NSArray *)address {NSMutableArray *rtnArray = [NSMutableArray array]; ABMultiValueRef address = ABRecordCopyValue(_recordRef, kABPersonAddressProperty);long count = ABMultiValueGetCount(address);for(int i = 0; i < count; i++){NSString* addressLabel = (__bridge NSString*)ABMultiValueCopyLabelAtIndex(address, i);NSDictionary* personaddress =(__bridge NSDictionary*) ABMultiValueCopyValueAtIndex(address, i);NSMutableDictionary *addressInfoDict = [NSMutableDictionary dictionary];NSString* country = [personaddress valueForKey:(NSString *)kABPersonAddressCountryKey];NSString* city = [personaddress valueForKey:(NSString *)kABPersonAddressCityKey];NSString* state = [personaddress valueForKey:(NSString *)kABPersonAddressStateKey];NSString* street = [personaddress valueForKey:(NSString *)kABPersonAddressStreetKey];NSString* zip = [personaddress valueForKey:(NSString *)kABPersonAddressZIPKey];NSString* coutntrycode = [personaddress valueForKey:(NSString *)kABPersonAddressCountryCodeKey];DICT_ADD_STR_FOR_KEY(addressInfoDict, country, @"country");DICT_ADD_STR_FOR_KEY(addressInfoDict, city,@"city");DICT_ADD_STR_FOR_KEY(addressInfoDict, state, @"state");DICT_ADD_STR_FOR_KEY(addressInfoDict, street, @"street");DICT_ADD_STR_FOR_KEY(addressInfoDict, zip,@"zip");DICT_ADD_STR_FOR_KEY(addressInfoDict, coutntrycode, @"coutntrycode");NSDictionary *addressDict = @{addressLabel: addressInfoDict};[rtnArray addObject:addressDict];}return rtnArray; }//- (UIImage *)image //{ // NSData *data = (__bridge NSData*)ABPersonCopyImageData(_recordRef); // return [UIImage imageWithData:data]; //}#pragma mark - #pragma mark - CustomProperty /*** 全名*/ - (NSString *)fullName {return [NSString stringWithFormat:@"%@%@%@", nullStrToEmpty(self.lastName), nullStrToEmpty(self.middlename), nullStrToEmpty(self.firstName)]; } /*** 首字母*/ - (NSString *)firstSpell {return getFirstSpell(self.fullName); }/*** 输出模型所有信息*/ - (NSString *)description {return [NSString stringWithFormat:@"%@ -- InfoPacket", self.fullName]; }/*** 获取首字母*/ NSString* getFirstSpell(NSString *fullName) {NSMutableString *ms = [[NSMutableString alloc] initWithString:fullName];CFStringTransform((__bridge CFMutableStringRef)ms, 0, kCFStringTransformMandarinLatin, NO);CFStringTransform((__bridge CFMutableStringRef)ms, 0, kCFStringTransformStripDiacritics, NO); if (fullName.length > 0)return [[ms substringWithRange:NSMakeRange(0, 1)] lowercaseString];elsereturn @"#"; }@end 
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。