美文网首页
iOS通讯录开发(排序、搜索、头像处理)

iOS通讯录开发(排序、搜索、头像处理)

作者: 西充小凡哥 | 来源:发表于2019-05-15 16:26 被阅读0次

    开发过一打电话的APP,把其中通讯录处理拿出来分享一下。
    先上效果图

    image

    .h

    #import <UIKit/UIKit.h>
    
    @protocol PhoneBookViewControllerDelegate <NSObject>
    
    /**
     * 返回联系人信息
     * @param phoneNote 电话备注
     * @param phones 电话号码数组
     */
    - (void)action_Note:(NSString *)phoneNote phones:(NSArray *)phones;
    
    @end
    
    @interface PhoneBookViewController : UIViewController
    @property (nonatomic, strong) NSArray *arrayWithTableV;
    @property (nonatomic, weak) id<PhoneBookViewControllerDelegate> delegate;
    
    /** 通讯录数据 <NSString,NSMutableArray>*/
    @property (nonatomic, strong) NSMutableDictionary       *dataSource;
    /** 首字母数组 <NSString>*/
    @property (nonatomic, strong) NSMutableArray            *sectionTitleArray;
    
    @end
    
    

    xib

    image

    cell xib

    image

    .m

    #import "PhoneBookViewController.h"
    #import <AddressBookUI/ABNewPersonViewController.h>
    #import <Contacts/Contacts.h>
    #import "PhoneBookTableViewCell.h"
    
    @interface PhoneBookViewController ()<UITableViewDelegate,UITableViewDataSource,ABNewPersonViewControllerDelegate,UITextFieldDelegate>
    @property (weak, nonatomic) IBOutlet UITableView *tableV;
    @property (weak, nonatomic) IBOutlet UIView *searchView;//搜索view
    @property (weak, nonatomic) IBOutlet UITextField *searchTextField;
    @property (weak, nonatomic) IBOutlet UIButton *closeButton;
    @property (weak, nonatomic) IBOutlet UIButton *cancelButton;
    @property (weak, nonatomic) IBOutlet UILabel *shadowLabel;
    
    @property (nonatomic, strong) NSMutableArray *arrayWithSearch;
    @property (weak, nonatomic) IBOutlet NSLayoutConstraint *tableVTop;
    
    /** 记录TableView开始搜索时的contentOffset */
    @property (nonatomic, assign) CGPoint oldPoint;
    
    @end
    
    @implementation PhoneBookViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        UIBarButtonItem *item = [UIBarButtonItem backItemWithImage:IMGNAME(@"返回") addTarget:self action:@selector(back) title:@"返回"];
        self.title = @"通讯录";
        self.navigationItem.leftBarButtonItem = item;
        self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]initWithImage:IMGNAME(@"新建联系人") style:UIBarButtonItemStylePlain target:self action:@selector(newPhone)];
        [self getUi];
    
        /** 在进入APP的时候获取通讯录(getContactList)并保存:Array -> 归档 -> UserDefaults  
          NSArray *arrayWithAddressBook = @[self.sectionTitleArray,self.dataSource];
          NSData *data = [NSKeyedArchiver archivedDataWithRootObject:arrayWithAddressBook];
          [[NSUserDefaults standardUserDefaults]setObject:data forKey:@"addressBook"];
        */
    
        //从UserDefaults里面获取缓存的通讯录
        //UserDefaults -> 解档(反归档) -> Array
        NSData *data = [[NSUserDefaults standardUserDefaults]objectForKey:@"addressBook"];
        NSArray *arrayWithAddressBook = [NSKeyedUnarchiver unarchiveObjectWithData:data];
        if (arrayWithAddressBook.count != 0) {
            self.sectionTitleArray = [arrayWithAddressBook[0] mutableCopy];
            self.dataSource = arrayWithAddressBook[1];
        }
      //如果UserDefaults里面没有就获取并保存通讯录信息
        if (self.arrayWithTableV.count == 0) {
            self.arrayWithTableV = [self getContactList];
            [self addressBookOrdering:self.arrayWithTableV];
        }
    
        //view适配代码  -> https://www.jianshu.com/p/a8eb3bbdc00f
        [XLBTools viewLayoutWithXib:self.view];
        [XLBTools viewLayoutWithXib:self.searchView];
        // Do any additional setup after loading the view from its nib.
    }
    - (void)back{
        NavBack(YES);
    }
    
    - (void)getUi{
        UIView *view = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 0, 0.0001)];
        self.tableV.tableHeaderView = view;
        [self.tableV registerNib:[UINib nibWithNibName:@"PhoneBookTableViewCell" bundle:nil] forCellReuseIdentifier:@"PhoneBookTableViewCell"];
    }
    
    #pragma mark - 新建联系人
    - (void)newPhone{
      //调用系统的新建联系人
        ABNewPersonViewController *picker = [[ABNewPersonViewController alloc]init];
        picker.newPersonViewDelegate = self;
        UINavigationController  *navigation = [[UINavigationController alloc]initWithRootViewController:picker];
        [self presentViewController:navigation animated:YES completion:^{
            //刷新UI
        }];
    }
    #pragma mark - ABNewPersonViewControllerDelegate
    - (void)newPersonViewController:(ABNewPersonViewController *)newPersonView didCompleteWithNewPerson:(nullable ABRecordRef)person{
        [newPersonView dismissViewControllerAnimated:YES completion:nil];
    }
    
    #pragma mark - 通讯录排序
    - (void)addressBookOrdering:(NSArray *)array{
        [self.sectionTitleArray removeAllObjects];
        [self.dataSource removeAllObjects];
        //赋初值 A~Z # 
            for (int i = 65; i < 91; i ++) {
                char c = (char)i;
                NSMutableArray *array = [NSMutableArray array];
                NSString *key = [NSString stringWithFormat:@"%c",c];
                [self.dataSource setObject:array forKey:key];
            }
            [self.dataSource setObject:[NSMutableArray array] forKey:@"#"];
    
            //遍历联系人信息
            for (CNContact *cnContact in array) {
                //备注名 
                NSString *name = [NSString stringWithFormat:@"%@%@",cnContact.familyName,cnContact.givenName];
                //判断是否有备注名
                if (name.length == 0) {
                    CNLabeledValue *lableValue = cnContact.phoneNumbers[0];
                    name = lableValue.label;
                }
                if (name.length == 0) {
                    NSArray *arrayWithPhone = cnContact.phoneNumbers;
                    CNLabeledValue *labelValue = arrayWithPhone[0];
                    CNPhoneNumber *phoneNumber = labelValue.value;
                    name = phoneNumber.stringValue;
                }
                //获取备注名首字母
                NSString *key = [self firstCharactorWithString:name];
                NSMutableArray *ar = self.dataSource[key];
                //保存备注名
                NSMutableDictionary *dic = [@{@"name":name} mutableCopy];
                NSMutableArray *phones = [NSMutableArray array];
                NSArray *arrayWithPhone = cnContact.phoneNumbers;
                for (CNLabeledValue *labelValue in arrayWithPhone) {
                    CNPhoneNumber *phoneNumber = labelValue.value;
                    [phones addObject:phoneNumber.stringValue];
                }
                //保存电话
                [dic setObject:phones forKey:@"phones"];
                NSData *data = cnContact.thumbnailImageData;
                UIImage *image = [UIImage imageWithData:data];
                //保存头像
                if (image == nil) {
                    [dic setObject:@"" forKey:@"header"];
                } else{
                    [dic setObject:image forKey:@"header"];
                }
                 [ar addObject:dic];
                //保存联系人信息
                [self.dataSource setObject:ar forKey:key];
            }
            //删除多余的分类
            for (NSString *key in self.dataSource.allKeys) {
                NSArray *array = self.dataSource[key];
                if (array.count == 0) {
                    [self.dataSource removeObjectForKey:key];
                }
            }
                self.closeButton.hidden = YES;
                [self.tableV reloadData];
    }
    
    #pragma mark - 通讯录搜索
    - (void)searchPhone{
        [self.arrayWithSearch removeAllObjects];
        //搜索关键字(可以是数字、文字)
        NSString *searchText = self.searchTextField.text;
        if (searchText.length == 0) {
            [self addressBookOrdering:self.arrayWithTableV];
            self.closeButton.hidden = NO;
            [self.tableV layoutIfNeeded];
            [self.tableV setContentOffset:self.oldPoint animated:NO];
            return;
        }
        //遍历获取搜索数据
        for (CNContact *cnContact in self.arrayWithTableV) {
            NSString *name = [NSString stringWithFormat:@"%@%@",cnContact.familyName,cnContact.givenName];
            if (!([name rangeOfString:searchText].location == NSNotFound) ) {
                [self.arrayWithSearch addObject:cnContact];
                continue;
            }
            NSArray *arrayWithPhone = cnContact.phoneNumbers;
            for (int i = 0; i < arrayWithPhone.count; i ++) {
                CNLabeledValue *labelValue = arrayWithPhone[i];
                CNPhoneNumber *phoneNumber = labelValue.value;
                name = labelValue.label;
                if (!([name rangeOfString:searchText].location == NSNotFound) ) {
                    [self.arrayWithSearch addObject:cnContact];
                    break;
                }
                name = [self dealWithPhone:phoneNumber.stringValue];
                if (!([name rangeOfString:searchText].location == NSNotFound) ) {
                    [self.arrayWithSearch addObject:cnContact];
                    break;
                }
            }
        }
        //对搜索数据进行排序展示
        [self addressBookOrdering:self.arrayWithSearch];
        //因为使用同一个tableView所以滑动到顶部
        [self.tableV layoutIfNeeded];
        [self.tableV setContentOffset:CGPointMake(0, 0) animated:NO];
    }
    
    /** 处理手机号 */
    - (NSString *)dealWithPhone:(NSString *)phone{
        NSString *phoneNum = [NSString stringWithFormat:@"%@",phone];
        phoneNum = [phoneNum stringByReplacingOccurrencesOfString:@" " withString:@""];
        phoneNum = [phoneNum stringByReplacingOccurrencesOfString:@"-" withString:@""];
        phoneNum = [phoneNum stringByReplacingOccurrencesOfString:@"+86" withString:@""];
        phoneNum = [phoneNum stringByReplacingOccurrencesOfString:@"," withString:@""];
        return phoneNum;
    }
    
    #pragma mark - 获取通讯录列表
    -(NSMutableArray*)getContactList{
    
        NSMutableArray *array = [NSMutableArray array];
        //获取授权状态
        CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
        //判断授权状态,如果不是已经授权,则直接返回
        if (status != CNAuthorizationStatusAuthorized) {
            return nil;
        }
        //创建通信录对象
        CNContactStore *contactStore = [[CNContactStore alloc] init];
        // 4.1.拿到所有打算获取的属性对应的key
        NSArray *keys = @[CNContactGivenNameKey, CNContactFamilyNameKey, CNContactPhoneNumbersKey,CNContactImageDataKey,CNContactThumbnailImageDataKey,CNContactImageDataAvailableKey];
        // 4.2.创建CNContactFetchRequest对象
        CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:keys];
        // 5.遍历所有的联系人
        [contactStore enumerateContactsWithFetchRequest:request error:nil usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) {
            [array addObject:contact];
        }
         ];
        return array;
    
    }
    //获取某个字符串或者汉字的首字母.
    - (NSString *)firstCharactorWithString:(NSString *)string
    {
        NSMutableString *str = [NSMutableString stringWithString:string];
        CFStringTransform((CFMutableStringRef) str, NULL, kCFStringTransformMandarinLatin, NO);
        CFStringTransform((CFMutableStringRef)str, NULL, kCFStringTransformStripDiacritics, NO);
        NSString *pinYin = [str capitalizedString];
        if (pinYin.length == 0) {
            return @"#";
        }
        unichar c = [pinYin characterAtIndex:0];
        if (c <'A'|| c >'Z'){
            return @"#";
        }
        NSCharacterSet *notDigits = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
        if ([[pinYin substringToIndex:1] rangeOfCharacterFromSet:notDigits].location == NSNotFound){
            // 是数字
            return @"#";
        }
        if ([[pinYin substringToIndex:1] isEqual:@"_"]) {
            return @"#";
        }
        return [pinYin substringToIndex:1];
    }
    
    #pragma mark - TableViewDelegate
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
        return self.sectionTitleArray.count;
    }
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
        NSArray *array = [self.dataSource valueForKey:self.sectionTitleArray[section]];
        return array.count;
    }
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
        return ADAPTATION_HEIGHT(67);
    }
    - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
        return ADAPTATION_HEIGHT(25);
    }
    - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
        UIView *view = [[UIView alloc]initWithFrame:CGRectMake(0, 0, MAINSCREEN_WIDTH, ADAPTATION_HEIGHT(24))];
        UILabel *label = [[UILabel alloc]init];
        label.text = [NSString stringWithFormat:@"%@",self.sectionTitleArray[section]];
        [view addSubview:label];
        label.textColor = GetColor(26, 26, 26, 1);
        label.font = FONT(18);
        label.frame = CGRectMake(ADAPTATION_WIDTH(11), 0, 100, ADAPTATION_HEIGHT(25));
        return view;
    }
    - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{
        return 0.0001;
    }
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
        PhoneBookTableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"PhoneBookTableViewCell" forIndexPath:indexPath];
        cell.selectionStyle = UITableViewCellSelectionStyleNone;
        NSArray *array = [self.dataSource valueForKey:self.sectionTitleArray[indexPath.section]];
        NSDictionary *dic = array[indexPath.row];
        NSString *name = dic[@"name"];
        NSCharacterSet *set = [NSCharacterSet whitespaceAndNewlineCharacterSet];
        name = [name stringByTrimmingCharactersInSet:set];
        cell.name.text = name;
        id image = dic[@"header"];
        if ([image isKindOfClass:[UIImage class]]) {
            cell.headerImage.image = dic[@"header"];
        } else{
            cell.headerImage.image = nil;
        }
        NSString *headerName = [name substringWithRange:NSMakeRange(name.length - 1, 1)];
        cell.phoneNameImage.text = headerName;
        NSInteger num = arc4random() % 5;
        switch (num) {
            case 1:
                cell.phoneNameImage.backgroundColor = GetColor(134,185,255, 1);
                break;
            case 2:
                cell.phoneNameImage.backgroundColor = GetColor(134,234,255, 1);
                break;
            case 3:
                cell.phoneNameImage.backgroundColor = GetColor(129,212,255, 1);
                break;
            case 4:
                cell.phoneNameImage.backgroundColor = GetColor(245,175,255, 1);
                break;
            default:
                break;
        }
        return cell;
    }
    
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
        NSArray *array = [self.dataSource valueForKey:self.sectionTitleArray[indexPath.section]];
        NSDictionary *dic = array[indexPath.row];
        NSString *name = dic[@"name"];
        NSArray *phones = dic[@"phones"];
        NSLog(@"备注:%@,电话:%@",name,phones);
        if (phones.count > 1) {
            [self choosePhone:phones name:name];
        } else{
        if (_delegate && [self.delegate respondsToSelector:@selector(action_Note:phones:)]) {
            [self.delegate action_Note:name phones:phones];
            [self back];
        }
        }
    }
    //选择电话号码
    - (void)choosePhone:(NSArray *)phones name:(NSString *)name{
        [self.view endEditing:YES];
        UIAlertController *alter = [UIAlertController alertControllerWithTitle:@"" message:@"请选择号码" preferredStyle:UIAlertControllerStyleActionSheet];
        for (int i = 0 ; i < phones.count; i++) {
            NSString *phone = phones[i];
            UIAlertAction *action = [UIAlertAction actionWithTitle:phone style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
                [self chooseType:name phone:@[phone]];
            }];
    
            [alter addAction:action];
        }
        UIAlertAction *actionCancel = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];
        [alter addAction:actionCancel];
        [self presentViewController:alter animated:YES completion:nil];
    }
    - (void)chooseType:(NSString *)name phone:(NSArray *)phones{
        if (_delegate && [self.delegate respondsToSelector:@selector(action_Note:phones:)]) {
            [self.delegate action_Note:name phones:phones];
            [self back];
        }
    }
    
    - (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
    {
        return self.sectionTitleArray;
    }
    #pragma mark - UITextFieldDelegate
    - (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
        [self hiddenNavView];
        return YES;
    }
    - (IBAction)textFieldValueChange:(UITextField *)sender {
        [self searchPhone];
    }
    -(BOOL)textFieldShouldReturn:(UITextField *)textField{
        [textField endEditing:YES];
        [self searchPhone];
        return YES;
    }
    //开始搜索
    - (void)hiddenNavView{
        if (self.navigationController.navigationBar.hidden == YES) {
            return;
        }
        self.oldPoint = self.tableV.contentOffset;
        for (UIView *view in self.searchView.subviews) {
            CGRect rect = view.frame;
            if (iPhoneX) {
                rect.origin.y = rect.origin.y + 33;
            } else{
                rect.origin.y = rect.origin.y + 14;
            }
    
            view.frame = rect;
        }
        [UIView animateWithDuration:0.3 animations:^{
            NavHidden(YES);
            CGRect searchRect = self.searchView.frame;
            if (iPhoneX) {
                searchRect.size.height = 88;
            } else{
                searchRect.size.height = 64;
            }
    
            self.searchView.frame = searchRect;
            self.closeButton.hidden = NO;
            CGRect rect = self.searchTextField.frame;
            rect.size.width = ADAPTATION_WIDTH(254);
            self.searchTextField.frame = rect;
            CGRect cancelRect = self.cancelButton.frame;
            cancelRect.origin.x = ADAPTATION_WIDTH(330);
            self.cancelButton.frame = cancelRect;
            CGRect shadowRect = self.shadowLabel.frame;
            shadowRect.size.width = shadowRect.size.width - ADAPTATION_WIDTH(40);
            self.shadowLabel.frame = shadowRect;
    
            self.tableVTop.constant = self.searchView.frame.size.height;
        }];
    }
    //取消搜索
    - (IBAction)showNavView{
        self.searchTextField.text = @"";
        [self addressBookOrdering:self.arrayWithTableV];
        //tableview滑动到搜索之前所在位置
        [self.tableV layoutIfNeeded];
        [self.tableV setContentOffset:self.oldPoint animated:NO];
        for (UIView *view in self.searchView.subviews) {
            CGRect rect = view.frame;
            if (iPhoneX) {
                rect.origin.y = rect.origin.y - 33;
            } else{
                rect.origin.y = rect.origin.y - 14;
            }
            view.frame = rect;
        }
        [self.searchTextField endEditing:YES];
        [UIView animateWithDuration:0.3 animations:^{
            NavHidden(NO);
            CGRect searchRect = self.searchView.frame;
            searchRect.size.height = ADAPTATION_HEIGHT(51);
            self.searchView.frame = searchRect;
            self.closeButton.hidden = YES;
            CGRect rect = self.searchTextField.frame;
            rect.size.width = ADAPTATION_WIDTH(318);
            self.searchTextField.frame = rect;
            CGRect cancelRect = self.cancelButton.frame;
            cancelRect.origin.x = MAINSCREEN_WIDTH + 1;
            self.cancelButton.frame = cancelRect;
            CGRect shadowRect = self.shadowLabel.frame;
            shadowRect.size.width = shadowRect.size.width + ADAPTATION_WIDTH(40);
            self.shadowLabel.frame = shadowRect;
            self.tableVTop.constant = self.searchView.frame.size.height;
        }];
    
    }
    #pragma mark - 视图生命周期
    - (void)viewWillAppear:(BOOL)animated{
    
    }
    - (void)viewDidAppear:(BOOL)animated{
        // 判断是否是从新建页面返回
        if (![self isMovingToParentViewController]) {
            self.arrayWithTableV = [self getContactList];
            [self addressBookOrdering:self.arrayWithTableV];
        }
    }
    
    #pragma mark - Getter/Setter
    - (void)setArrayWithTableV:(NSArray *)arrayWithTableV{
        _arrayWithTableV = arrayWithTableV;
    }
    - (void)setDataSource:(NSMutableDictionary *)dataSource{
        _dataSource = dataSource;
    }
    - (NSMutableArray *)sectionTitleArray {
        _sectionTitleArray = [[self.dataSource allKeys] mutableCopy];
        for (NSInteger i = 0; i < _sectionTitleArray.count; i++) {
            for (NSInteger j = _sectionTitleArray.count - 1; j > i; j--) {
                if (_sectionTitleArray[i] > _sectionTitleArray[j]) {
                    NSString *temp = _sectionTitleArray[i];
                    [_sectionTitleArray replaceObjectAtIndex:i withObject:_sectionTitleArray[j]];
                    [_sectionTitleArray replaceObjectAtIndex:j withObject:temp];
                }
            }
        }
        [_sectionTitleArray removeObject:@"#"];
        [_sectionTitleArray addObject:@"#"];
        return _sectionTitleArray;
    }
    - (NSMutableArray *)arrayWithSearch{
        if (!_arrayWithSearch) {
            _arrayWithSearch = [NSMutableArray array];
        }
        return _arrayWithSearch;
    }
    
    

    转载:https://www.jianshu.com/u/f52751405238

    相关文章

      网友评论

          本文标题:iOS通讯录开发(排序、搜索、头像处理)

          本文链接:https://www.haomeiwen.com/subject/xnxmaqtx.html