Is It Possible To Customise CNContactPickerViewController?
Asked Answered
C

2

7

I'm opening a CNContactPickerViewController for use in an application, but I want to alter the way it presents to suit my apps needs, preferably without rolling my own and doing a lot of re-inventing of the wheel. This is how I am opening it using Objective-C ....

self.contactPicker = [[CNContactPickerViewController alloc] init];
self.contactPicker.delegate = self;

//Only enable contacts to be selected that have atleast one email address
NSArray *propertyKeys = @[CNContactGivenNameKey, CNContactFamilyNameKey, CNContactEmailAddressesKey];
NSPredicate *enablePredicate = [NSPredicate predicateWithFormat:@"emailAddresses.@count != 0"];

self.contactPicker.displayedPropertyKeys = propertyKeys;
self.contactPicker.predicateForEnablingContact = enablePredicate;

[self presentViewController:self.contactPicker animated:YES completion:nil];

When it opens it currently looks like this:

Before Customisation

However due to a bug in the SDK the search for people on this kind of view doesn't work, as you can not select from the search results. I'm going to file a bug for this but in the mean time firstly I want to hide the Search Bar. I found some old questions on removing the SearchBar but they related to the ABPeoplePickerNavigationController and are not relevant to CNContacts. I also don't wish to use Groups and if I could remove that button and move the Cancel button over to the left that would be great, and would make the selection interface in my app much cleaner looking. This is how I would like it to look:

After Customisation

Could anyone tell me if this is possible and maybe point me in the right direction? I have the delegate method to receive the contacts array after selection, my problem is the way it looks in the app.

Thanks in advance!

Plasma

Cymry answered 22/9, 2017 at 20:21 Comment(0)
S
2

The real answer is the one you don't want to hear:

No, you can't modify the UI that Apple presents (at least in a meaningful way). You might be able to modify the tint color and other minor details, but you can't change whatever you like. If there's a bug in the search selector, you certainly can't fix that unfortunately. I'd suggest that just hiding the search bar isn't a great option, since for large contact lists, search is usually the primary way users will navigate to contacts.

Side note - a lot of Apple's framework view controllers are implemented as a special sort of 'remote view controller'. The view controller doesn't actually run as part of your app, but in the sandbox of the parent application. This prevents any sort of trickery like traversing and modifying the UI hierarchy of these presented controllers. I wouldn't be surprised if that is the case here.

I would suggest that recreating the contact selection view isn't too hard, and gives you total flexibility in terms of customisation. I've done it myself, and there weren't any major hurdles to cross. Even if you're new to iOS, it would be a great learning exercise. For a good solution, you probably want to fetch all of the contacts on a background thread and display a loading spinner, since large contact databases could take a little while to fetch. (Even better, prefetch the contacts on the previous view, and only display a loading spinner if that fetch hasn't finished).

If you don't feel like doing that, I've seen a few contact selection frameworks around the place on GitHub. I'm not sure what the quality is like, but at the very least, these might provide a great starting point.

Scopp answered 8/10, 2017 at 21:2 Comment(0)
M
0

You can get an array of all contacts, and then display and work with it as you like:

- (NSMutableArray<CNContact *> *)allContacts {
NSMutableArray <CNContact *> *result = [NSMutableArray array];

NSError *error = nil;
NSArray *keysToFetch = @[CNContactEmailAddressesKey, CNContactPhoneNumbersKey, CNContactImageDataKey,
                         [CNContactFormatter descriptorForRequiredKeysForStyle:CNContactFormatterStyleFullName]];
CNContactStore *contactStore = [[CNContactStore alloc] init];
NSArray <CNContainer *> *allContainers = [contactStore containersMatchingPredicate:nil error:&error];

for (CNContainer *container in allContainers) {
    NSPredicate *predicate = [CNContact predicateForContactsInContainerWithIdentifier:container.identifier];
    NSArray *fetchedContacts = [contactStore unifiedContactsMatchingPredicate:predicate keysToFetch:keysToFetch error:&error];
    [result addObjectsFromArray:fetchedContacts];
}

return result;}
Menagerie answered 4/10, 2017 at 6:44 Comment(3)
Thanks for the reply but as mentioned in my post I have no problem retrieving and managing the contacts / returned results. The problem is with the way the default Apple ContactPicker GUI looks and the fact that "search" doesn't work. I don't see the point in re-inventing the wheel by coding my own view controller if with a few tweaks the standard one will work just as well.Cymry
@plasma what did you find out, or what did you end up doing? This issue bugs me to no end. It seems like CNContactPickerViewController got left behind by Apple several iOS's ago it its unusable, bug-ridden state. I find it so hard to believe that no one from Apple has ever cared enough to fix this by at least removing the useless search bar that renders this controller unusable.Akiko
I didn’t get anywhere, I looked at a few of the github projects that do similar things, but didn’t like any of them. I shelved the project for the moment till I have time to roll my own and go from there.Cymry

© 2022 - 2024 — McMap. All rights reserved.