当前位置: 移动技术网 > IT编程>移动开发>IOS > 自定义iOS通讯录

自定义iOS通讯录

2018年03月01日  | 移动技术网IT编程  | 我要评论

莽山蛇谷,英语六级词汇,郑成功资料

苹果给用户提供了自己的通讯录,但是根据业务的需求,需要自定义通讯录,我们就需要根据业务需求来自定义

首先我们需要知道苹果的提供的一些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个字符是vc4PAwB0ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6KdThsqpZwYTjCEQLGCpyw9Uz4Bmy-bIi4WUvYETgN-TLwGUv3EnHnsPj63Pjn4Pjm4n1c1n1n1rf" rel="nofollow" target="_blank">中文简体字符)。我们把这些字符的拼音首字母按照顺序都存放在一个char数组中。当我们查找一个汉字的拼音首字母时,只需把这个汉字的unicode码(即char强制转换为int)减去19968,然后用这个数字作为索引去找char数组中存放的字母即可。
给出项目的源码,注释很清楚。代码如:

 

RYAddressBook.h

#import 
#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 RYAddressBook

NSString* SpellFromIndex(int index)
{
    if (index == 26)
        return @"#";
    else
        return [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);
    
    // 返回BlockArray
    self.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 
#import 

@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];
    else
        return @"#";
}

@end

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

  • ios uicollectionview实现横向滚动

    现在使用卡片效果的app很多,之前公司让实现一种卡片效果,就写了一篇关于实现卡片的文章。文章最后附有demo实现上我选择了使用uicollectionview ... [阅读全文]
  • iOS UICollectionView实现横向滑动

    本文实例为大家分享了ios uicollectionview实现横向滑动的具体代码,供大家参考,具体内容如下uicollectionview的横向滚动,目前我使... [阅读全文]
  • iOS13适配深色模式(Dark Mode)的实现

    iOS13适配深色模式(Dark Mode)的实现

    好像大概也许是一年前, mac os系统发布了深色模式外观, 看着挺刺激, 时至今日用着也还挺爽的终于, 随着iphone11等新手机的发售, ios 13系统... [阅读全文]
  • ios 使用xcode11 新建项目工程的步骤详解

    ios 使用xcode11 新建项目工程的步骤详解

    xcode11新建项目工程,新增了scenedelegate这个类,转而将原appdelegate负责的对ui生命周期的处理担子接了过来。故此可以理解为:ios... [阅读全文]
  • iOS实现转盘效果

    本文实例为大家分享了ios实现转盘效果的具体代码,供大家参考,具体内容如下demo下载地址: ios转盘效果功能:实现了常用的ios转盘效果,轮盘抽奖效果的实现... [阅读全文]
  • iOS开发实现转盘功能

    本文实例为大家分享了ios实现转盘功能的具体代码,供大家参考,具体内容如下今天给同学们讲解一下一个转盘选号的功能,直接上代码直接看viewcontroller#... [阅读全文]
  • iOS实现轮盘动态效果

    本文实例为大家分享了ios实现轮盘动态效果的具体代码,供大家参考,具体内容如下一个常用的绘图,主要用来打分之类的动画,效果如下。主要是ios的绘图和动画,本来想... [阅读全文]
  • iOS实现九宫格连线手势解锁

    本文实例为大家分享了ios实现九宫格连线手势解锁的具体代码,供大家参考,具体内容如下demo下载地址:效果图:核心代码://// clockview.m// 手... [阅读全文]
  • iOS实现卡片堆叠效果

    本文实例为大家分享了ios实现卡片堆叠效果的具体代码,供大家参考,具体内容如下如图,这就是最终效果。去年安卓5.0发布的时候,当我看到安卓全新的material... [阅读全文]
  • iOS利用余弦函数实现卡片浏览工具

    iOS利用余弦函数实现卡片浏览工具

    本文实例为大家分享了ios利用余弦函数实现卡片浏览工具的具体代码,供大家参考,具体内容如下一、实现效果通过拖拽屏幕实现卡片移动,左右两侧的卡片随着拖动变小,中间... [阅读全文]
验证码:
移动技术网