The Facebook SDK for iOS includes an FBFriendPickerViewController
control object that makes it simple to add a friend selector to your app. By default, the friend selector does not include the ability to filter friends. This article guides you through adding search functionality to the friend selector.
This document walks through the following topics:
Before you begin, make sure you've already set up Facebook Login. This ensures that you have the prerequisites and your app is ready for additional Facebook integration.
The completed sample allows users to log in with Facebook and select their friends. Users can also search for specific friends. In this simple sample, we'll echo back the selected friends.
The implementation builds on top of Login with Facebook, adding a button the user can click to show the friend selector. The friend selector is configured to display done and cancel buttons that allow users to dismiss the picker. A search bar is added to the friend selector view controller's view and the cancel button is enabled in the search bar to enable users to cancel and start a new search.
The friend selector is displayed using the FBFriendPickerViewController
Facebook SDK object. After the object is initialized, the loadData
instance method is called to load and setup the initial friend selection. The friend selector is displayed modally using the presentModalViewController:animated:
view controller method. This method is deprecated in iOS 5+, but you use it here to support earlier versions of iOS.
The FBFriendPickerDelegate
methods are defined to handle the friend selector cancel and done button actions. If the done button is selected, the selected friends echo through NSLog
. In both cases, the modal view controller is dismissed.
Search functionality is implemented with the UISearchBar
control element. The showsCancelButton
property is enabled in the search bar instance to expose the cancel button, allowing users to cancel the search and dismiss the keyboard. The UISearchBarDelegate
methods are defined to detect the cancel and search buttons. If the search button is clicked, the search query is saved and the updateView
method is invoked on the FBFriendPickerViewController
instance to reload friend information without making a server roundtrip. The friendPickerViewController:shouldIncludeUser:
delegate of the FBFriendPickerDelegate
class is implemented to filter the friend data.
Now that you have an overview of the UI and functionality, let's show you the code.
In this step, you'll add a button in the initial view controller. When the user clicks the button, the friend selector displays.
Make the following changes in your main view controller's nib file:
Round Rect Button
object to the view. Set the button title to ''Select Friends''.When you've completed these steps, your implementation file should have the defined outlet and an empty selectFriendsButtonAction:
action method.
If you followed the Login with Facebook doc, you should have a sessionStateChanged:
method defined in your view controller implementation file that controls the logged-in and logged-out UI. Modify this method to show the friend selector button only when the user is authenticated:
- (void)sessionStateChanged:(NSNotification*)notification { if (FBSession.activeSession.isOpen) { self.selectFriendsButton.hidden = NO; [self.authButton setTitle:@"Logout" forState:UIControlStateNormal]; } else { self.selectFriendsButton.hidden = YES; [self.authButton setTitle:@"Login" forState:UIControlStateNormal]; } }
In this step, you setup a basic friend selector that does not include search functionality. When the user is shown the friend selector, they can pick one or more friends and tap a done button. The friend selections are echoed back to the Xcode console.
Add the FBFriendPickerDelegate
as one of the protocols the view controller implementation conforms to. Add this delegate to the view controller implementation.
@interface ViewController ()
<FBFriendPickerDelegate>
Add a private property to store the friend selector instance:
@property (retain, nonatomic) FBFriendPickerViewController *friendPickerController;
Synthesize this property:
@synthesize friendPickerController = _friendPickerController;
Set the picker view controller property to nil
when the view unloads by adding this to the end of the viewDidUnload
method:
self.friendPickerController = nil;
Next, complete the implementation for the ''Select Friends'' button action. Your code initializes the FBFriendPickerViewController
instance, assigns the current FBSession
to the friend selector, sets up the view controller class as the delegate for the friend selector, loads the friend data before modally presenting the friend selector:
- (IBAction)selectFriendsButtonAction:(id)sender { if (self.friendPickerController == nil) { // Create friend picker, and get data loaded into it. self.friendPickerController = [[FBFriendPickerViewController alloc] init]; self.friendPickerController.title = @"Select Friends"; self.friendPickerController.delegate = self; } [self.friendPickerController loadData]; [self.friendPickerController clearSelection]; [self presentModalViewController:self.friendPickerController animated:YES]; }
Next, handle what happens when the friend selector done and cancel buttons are clicked. In both cases, the modal view controller should be dismissed.
Add a private helper method that you can call to dismiss the friend selector:
- (void) handlePickerDone { [self dismissModalViewControllerAnimated:YES]; }
This helper method is invoked from the FBFriendPickerDelegate
delegate methods that handle done and cancel actions:
- (void)facebookViewControllerCancelWasPressed:(id)sender { NSLog(@"Friend selection cancelled."); [self handlePickerDone]; } - (void)facebookViewControllerDoneWasPressed:(id)sender { for (id<FBGraphUser> user in self.friendPickerController.selection) { NSLog(@"Friend selected: %@", user.name); } [self handlePickerDone]; }
Build and run the project to make sure it runs without errors. Tap the ''Login'' button to log in with Facebook. Once you're authenticated, you should see the ''Select Friends'' button. Click Select Friends to show the friend selector. The search bar should not display yet.
In this step, you'll add the search bar to the friend selector, and implement search delegate functions to save the query and initiate a friend selector reload. As part of the reload, you'll implement the FBFriendPickerDelegate
delegate method that filters and shows friends that meet the search criteria.
Add a new private property to define the search bar and the search query text:
@property (retain, nonatomic) UISearchBar *searchBar; @property (retain, nonatomic) NSString *searchText;
Synthesize these new properties:
@synthesize searchBar = _searchBar; @synthesize searchText = _searchText;
Set the search bar property to nil
when the view unloads by adding this code to the end of the viewDidUnload
method:
self.searchBar = nil;
Add the UISearchBarDelegate
as one of the protocols the view controller implementation conforms to in the view controller implementation's interface.
Define a new private method that adds the search bar to the friend selector view. After the search bar is initialized, configured and properly sized, it is added to the canvasView
property of the FBFriendPickerViewController
instance. The canvasView
property is inherited from the FBViewController
class and you should add the search bar to this view so it properly resizes when a toolbar displays:
- (void)addSearchBarToFriendPickerView { if (self.searchBar == nil) { CGFloat searchBarHeight = 44.0; self.searchBar = [[UISearchBar alloc] initWithFrame: CGRectMake(0,0, self.view.bounds.size.width, searchBarHeight)]; self.searchBar.autoresizingMask = self.searchBar.autoresizingMask | UIViewAutoresizingFlexibleWidth; self.searchBar.delegate = self; self.searchBar.showsCancelButton = YES; [self.friendPickerController.canvasView addSubview:self.searchBar]; CGRect newFrame = self.friendPickerController.view.bounds; newFrame.size.height -= searchBarHeight; newFrame.origin.y = searchBarHeight; self.friendPickerController.tableView.frame = newFrame; } }
Now that the search bar addition code is defined, you can call it when the FBFriendPickerViewController
displays. In iOS 5+, this can be done with the completion handler of the presentViewController:animated:completion: UIViewController
method. For iOS 4 versions, you don't have access to a completion handler to detect that the friend selector has displayed. We'll make use of flags to track when the friend selector is to be shown and use the viewDidDisappear:
method to detect the friend selector display and call the search bar addition code.
Define a property for the flag that is enabled when the friend selector is to be shown:
@property (assign, nonatomic) BOOL showingFriendPicker;
Synthesize this new property:
@synthesize showingFriendPicker = _showingFriendPicker;
In the viewDidAppear:
method, disable this flag:
- (void) viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; self.showingFriendPicker = NO; }
At the end of the viewDidDisappear:
method, add code to detect this flag and invoke the search bar:
- (void) viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; if (self.showingFriendPicker) { [self addSearchBarToFriendPickerView]; } }
Add the following code to the selectFriendsButtonAction:
method, just before the call to the presentModalViewController:animated:
method that presents the friend selector:
self.showingFriendPicker = YES;
There's one last piece in tracking this flag: when the picker is about to dismissed. Modify the handlePickerDone
method to turn off the flag before the modal view controller is dismissed:
- (void) handlePickerDone { self.showingFriendPicker = NO; [self dismissModalViewControllerAnimated:YES]; }
Note: If you are targeting iOS 5+ for your app, you can remove all references to the showingFriendPicker
property and make use of the presentViewController:animated:completion:
method to add the search bar at the proper time. You would then modify the selectFriendsButtonAction:
method by swapping out the presentModalViewController:
method call with the following:
[self presentViewController:self.friendPickerController animated:YES completion:^(void){ [self addSearchBarToFriendPickerView]; } ];
Now, create a new private helper method for the search functionality. This method dismisses the keyboard, saves the search query and reloads the friend data without a server call:
- (void) handleSearch:(UISearchBar *)searchBar { [searchBar resignFirstResponder]; self.searchText = searchBar.text; [self.friendPickerController updateView]; }
Implement these UISearchBarDelegate
methods:
- (void)searchBarSearchButtonClicked:(UISearchBar*)searchBar { [self handleSearch:searchBar]; } - (void)searchBarCancelButtonClicked:(UISearchBar *) searchBar { self.searchText = nil; [searchBar resignFirstResponder]; }
Finally, once the search query is captured and the friend data reloads, implement the following FBFriendPickerDelegate
method to show friends matching the query:
- (BOOL)friendPickerViewController:(FBFriendPickerViewController *)friendPicker shouldIncludeUser:(id<FBGraphUser>)user { if (self.searchText && ![self.searchText isEqualToString:@""]) { NSRange result = [user.name rangeOfString:self.searchText options:NSCaseInsensitiveSearch]; if (result.location != NSNotFound) { return YES; } else { return NO; } } else { return YES; } return YES; }
Build and run the project to make sure it runs without errors. Once you're authenticated, click Select Friends to show the friend selector. Test that the search functionality filters the friends displayed. Test that selecting a friend and tapping the done button closes the friend selector and displays the friends selected in the Xcode console. Test that clearing the search entry and hitting enter shows the original friend list.
FriendPickerSample
: simple sample from the SDK that shows a friend selector.