iosabaddressbookabpeoplepickerview

ABPeoplePickerNavigationController customisation


I want to use ABPeoplePickerNavigationController but I want to customise the view. I want to have an accessory image by some of the contacts, and I want to sort them in a different way than the default one. Is there a way to do it? Or do I have to create my own UITableViewController?


Solution

  • You'll have to create your own table view if you want to customize the appearance of the contacts in this manner. For example, you can extract the contacts using:

    - (void)loadContacts
    {
        ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus();
    
        if (status == kABAuthorizationStatusDenied) {
            // if you got here, user had previously denied/revoked permission for your
            // app to access the contacts, and all you can do is handle this gracefully,
            // perhaps telling the user that they have to go to settings to grant access
            // to contacts
    
            [[[UIAlertView alloc] initWithTitle:nil message:@"This app requires access to your contacts to function properly. Please visit to the \"Privacy\" section in the iPhone Settings app." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
            return;
        }
    
        CFErrorRef error = NULL;
        ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);
    
        if (error) {
            NSLog(@"ABAddressBookCreateWithOptions error: %@", CFBridgingRelease(error));
            if (addressBook) CFRelease(addressBook);
            return;
        }
    
        ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
            if (error) {
                NSLog(@"ABAddressBookRequestAccessWithCompletion error: %@", CFBridgingRelease(error));
            }
    
            dispatch_async(dispatch_get_main_queue(), ^{
                if (granted) {
                    // if they gave you permission, then get copy of contacts and reload table
    
                    self.allContacts = CFBridgingRelease(ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering(addressBook, NULL, kABPersonSortByLastName));
    
                    [self.tableView reloadData];
                } else {
                    // however, if they didn't give you permission, handle it gracefully, for example...
    
                    [[[UIAlertView alloc] initWithTitle:nil message:@"This app requires access to your contacts to function properly. Please visit to the \"Privacy\" section in the iPhone Settings app." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
                }
    
                if (addressBook) CFRelease(addressBook);
            });
        });
    }
    

    And you can then use this array in your cellForRowAtIndexPath:

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        static NSString *cellIdentifier = @"Cell";
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    
        ABRecordRef person = (__bridge ABRecordRef)self.allContacts[indexPath.row];
    
        NSMutableArray *nameArray = [NSMutableArray array];
    
        NSString *prefix    = CFBridgingRelease(ABRecordCopyValue(person, kABPersonPrefixProperty));
        if (prefix) [nameArray addObject:prefix];
    
        NSString *firstName = CFBridgingRelease(ABRecordCopyValue(person, kABPersonFirstNameProperty));
        if (firstName) [nameArray addObject:firstName];
    
        NSString *middleName = CFBridgingRelease(ABRecordCopyValue(person, kABPersonMiddleNameProperty));
        if (middleName) [nameArray addObject:middleName];
    
        NSString *lastName  = CFBridgingRelease(ABRecordCopyValue(person, kABPersonLastNameProperty));
        if (lastName) [nameArray addObject:lastName];
    
        NSString *fullname = [nameArray componentsJoinedByString:@" "];
    
        NSString *suffix    = CFBridgingRelease(ABRecordCopyValue(person, kABPersonSuffixProperty));
        if (suffix) {
            fullname = [NSString stringWithFormat:@"%@, %@", fullname, suffix];
        }
    
        cell.textLabel.text = fullname;
    
        NSString *company   = CFBridgingRelease(ABRecordCopyValue(person, kABPersonOrganizationProperty));
        if ([fullname length] == 0) {
            cell.textLabel.text = company;
            cell.detailTextLabel.text = nil;
        } else {
            cell.detailTextLabel.text = company;
        }
    
        if ([nameArray count] == 0 && [company length] == 0)
            NSLog(@"nothing to show!!!");
    
        return cell;
    }
    

    Obviously, given the entire idea was that you wanted to customize the cell, modify the cellForRowAtIndexPath accordingly, but hopefully this illustrates the idea.