Search code examples
iosobjective-cuinavigationcontrolleraddressbookui

ABPeoplePickerNavigationController shouldContinueAfterSelectingPerson return to search result


- (BOOL)peoplePickerNavigationController:
(ABPeoplePickerNavigationController *)peoplePicker
      shouldContinueAfterSelectingPerson:(ABRecordRef)person {

        DefaultContactSelectViewController *view = [[self storyboard] instantiateViewControllerWithIdentifier:@"DefaultContactView"];
        view.recordID  = recordID;
        view.phones = phones;
        view.emails = emails;
        view.first_name = first_name;
        view.last_name = last_name;
        view.delegate = self;

        [peoplePicker pushViewController:view animated:YES];
    return NO;
}

In the above code example, I'm pushing a custom contact view controller after selecting a contact. The problem is if the contact is selected from the search result, and then the user clicks back to get back to the contact picker, the search result will be cleared.

this problem does not happen if the above code return YES, but then it will push the default contact view which is not what I want.

Thanks in advance if you know how I can fix this issue.


Solution

  • You should probably write a custom PeoplePickerViewController since you'll never have enough control over Apple's default controller.

    Anyway, as for your current problem, here's what you need to do:

    Declare three new properties (use appropriate declarations based on if you are using ARC or not - I'm assuming no ARC)

    @property (nonatomic, assign) ABPeoplePickerNavigationController *peoplePicker;
    @property (nonatomic, assign) UIViewController *peoplePickerRootViewController;
    @property (nonatomic, copy) NSString *currentSearchString;
    

    Now, when you display people picker, add these lines:

    // save people picker when displaying
    self.peoplePicker = [[[ABPeoplePickerNavigationController alloc] init] autorelease];
    
    // save it's top view controller
    self.peoplePickerRootViewController = self.peoplePicker.topViewController;
    
    // need to see when view controller is shown/hidden - viewWillAppear:/viewWillDisappear: won't work so don't bother with it.
    self.peoplePicker.delegate = self;
    

    Now, we'll save search string just before pushing person view:

    - (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person
    {
        self.currentSearchString = nil;
        if ([self.peoplePickerRootViewController.searchDisplayController isActive])
        {
            self.currentSearchString = self.peoplePickerRootViewController.searchDisplayController.searchBar.text;
        }
        // other stuff... 
    

    Obviously, implement UINavigationControllerDelegate in this class. When the root view comes back into view, we will force display search results view. Here's the implementation for navigationController:willShowViewController:animated:

    - (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
    {
        if (navigationController == self.peoplePicker)
        {
            if (viewController == self.peoplePickerRootViewController)
            {
                if (self.currentSearchString)
                {
                    [self.peoplePickerRootViewController.searchDisplayController setActive: YES];
                    self.peoplePickerRootViewController.searchDisplayController.searchBar.text = self.currentSearchString;
                    [self.peoplePickerRootViewController.searchDisplayController.searchBar becomeFirstResponder];
                }
                self.currentSearchString = nil;
            }
        }
    }
    

    Don't forget to release currentSearchString in dealloc if not using ARC.

    Small caveat: There is a slight flicker when you select a person when ABPeoplePickerNavigationController is trying to hide the search results view.