My app needs to associate instances of a custom class with contact records in the iPhone's AddressBook. Everything's all well and good when I present the ABPeoplePickerNavigationController and allow the user to pick an existing contact. Problem is there's no obvious way to allow a user to easily ADD a contact record if the one they're looking for doesn't already exist in their AddressBook.
How are people getting from ABPeoplePickerNavigationController to ABNewPersonViewController in a way that's easy & intuitive for the user?
You can create a UIBarButton and add it to the UINavigationBar of the ABPeoplePickerNavigationController like so.
peoplePicker.topViewController.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(addPerson:)];
-(IBAction)addPerson:(id)sender{
ABNewPersonViewController *view = [[ABNewPersonViewController alloc] init];
view.newPersonViewDelegate = self;
UINavigationController *nc = [[UINavigationController alloc] initWithRootViewController:view];
[self.picker presentModalViewController:nc animated:YES];
}
The issue that i came up against was that the ABPeoplePickerNavigationController has a cancel button placed in the rightBarButtonItem slot and I had to update the navigation bar on the
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
I have documented the entire process on my blog with a worked example that should allow you to create a contacts style application similar to that on the iPhone. Hope this helps.
I found Scott Sherwood's approach along with the demo he posted on his site to be very helpful. As one of the commenters on his blog mentioned though, there is a problem with the Cancel button in Edit mode.
I just proposed a fix to Scott's demo, along with a different approach for the Person View Controller at:
http://finalize.com/2013/05/12/using-and-customizing-the-address-book-ui/
My suggestion for the Person View Controller was to put it up manually in the protocol method peoplePickerNavigationController:shouldContinueAfterSelectingPerson: for the ABPeoplePickerNavigationControllerDelegate.
// Displays the information of a selected person
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person
{
ABPersonViewController *view = [[ABPersonViewController alloc] init];
view.personViewDelegate = self;
view.displayedPerson = person; // Assume person is already defined.
view.allowsEditing = YES;
view.allowsActions = YES;
[peoplePicker pushViewController:view animated:YES];
return NO;
}
The only issue here is that the People Picker table view of names is not refreshed automatically after an edit. This can be fixed with the use of an Address Book callback. I show how this can be done in the GitHub project I posted at:
https://github.com/scottcarter/AddressBookPeoplePicker.git
it appears that it is not possible to add a new contact directly from the ABPeoplePickerNavigationController. Therefore, when the user clicks an add button, I am presenting an UIActionSheet with two buttons:
- (void) addContact{
contactMenu = [[UIActionSheet alloc]
initWithTitle: nil
delegate:self
cancelButtonTitle:#"Cancel"
destructiveButtonTitle: nil
otherButtonTitles:#"Select a contact", #"Add a new contact", NULL];
[contactMenu showInView:self.view];
}
Here is the associated delegate method:
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(buttonIndex == 0){
// select an existing contact
ABPeoplePickerNavigationController *peoplePicker = [[ABPeoplePickerNavigationController alloc] init];
peoplePicker.peoplePickerDelegate = self;
[self presentModalViewController:peoplePicker animated:YES];
}
if(buttonIndex == 1){
// add a new contact
ABNewPersonViewController *newPersonViewController = [[ABNewPersonViewController alloc] init];
newPersonViewController.newPersonViewDelegate = self;
UINavigationController *personNavController = [[UINavigationController alloc] initWithRootViewController:newPersonViewController];
[self presentModalViewController:personNavController animated:YES];
[personNavController release];
[newPersonViewController release];
}
if(buttonIndex == 2){
// cancel the operation
[actionSheet dismissWithClickedButtonIndex:2 animated:YES];
}
}
Related
I have an iOS TabBar Application with tabbarcontroller and navigationcontroller.
In my detail view wich is pushed from my first tab tableviewcontroller i have sharing navigationItem.rightBarButtonItem with email sharing.
I have the following code for this:
- (void)share
{
UIActionSheet *popupQuery = [[UIActionSheet alloc] initWithTitle:#"Send" delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:nil otherButtonTitles:#"Email",nil];
popupQuery.actionSheetStyle = UIActionSheetStyleBlackTranslucent;
[popupQuery showInView:self.view];
[popupQuery release];
}
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0) {
if ([MFMailComposeViewController canSendMail]){
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
[picker setMailComposeDelegate:self];
[picker setSubject:#"New theme"];
NSString *emailBody = #"Hi there";
[picker setMessageBody:emailBody isHTML:NO];
[self resignFirstResponder];
picker.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
picker.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentModalViewController:picker animated:NO];
[picker release];
}
else{
}
}
}
The app shows me the composing view but when i'm trying to do something with this view (e.g. to pick up the address or to spell something) - app crashes with SIGTRAP.
The app crashes only in iOS5, iOS5.1. In iOS4.2.1 everything works perfect.
What's the problem? Any ideas?
Per the docs, I'd suggest calling [MFMailComposeViewController canSendMail] class method before creating MFMailComposeViewController. I also generally don't have that [self resignFirstResponder] line. I gather you're crashing before your mailComposeController:didFinishWithResult:error method is invoked?
Thank you guys for your help and your time.
It was absolutely insane bug. Project has a cyrillic name. I just renamed it to latin name and now everything works fine. My fault :( Thanks Evgeniy Shurakov for the help.
In my appController's ViewDidLoad, I have done some thing as below
- (void)viewDidLoad
{
self.overlayViewController =
[[[OverlayViewController alloc] initWithNibName:#"OverlayViewController" bundle:nil] autorelease];
// as a delegate we will be notified when pictures are taken and when to dismiss the image picker
self.overlayViewController.delegate = self;
self.capturedImages = [NSMutableArray array];
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
{
// camera is not on this device, don't show the camera button
NSMutableArray *toolbarItems = [NSMutableArray arrayWithCapacity:self.myToolbar.items.count];
[toolbarItems addObjectsFromArray:self.myToolbar.items];
[toolbarItems removeObjectAtIndex:2];
[self.myToolbar setItems:toolbarItems animated:NO];
}
}
I have two methods as below,
- (IBAction)cameraAction:(id)sender
{
[self showImagePicker:UIImagePickerControllerSourceTypeCamera];
}
- (void)showImagePicker:(UIImagePickerControllerSourceType)sourceType
{
if (self.imageView.isAnimating)
self.imageView.stopAnimating;
if (self.capturedImages.count > 0)
[self.capturedImages removeAllObjects];
if ([UIImagePickerController isSourceTypeAvailable:sourceType])
{
[self.overlayViewController setupImagePicker:sourceType];
[self presentModalViewController:self.overlayViewController.imagePickerController animated:YES];
}
}
Now as I click the button, the method will launch the class showing custom view, I want to call this without clicking the button, what should I do ?
I wrote the button coding directly in ViewDidLoad, but not working at all
This code, I took from apple's documentation as example
Help !
If I understand correctly, you are wanting to show a view?
If so you could push using:
[self.navigationcontroller pushviewcontroller:YOURVIEWCONTROLLER animated:YES];
Or you could present it using:
[self presentModalViewControllerpushviewcontroller:YOURVIEWCONTROLLER animated:YES];
I am trying to integrate new contact control in my app. Here is my code:
- (BOOL) personViewController:(ABPersonViewController*)personView shouldPerformDefaultActionForPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifierForValue
{
return YES;
}
-(IBAction)addcontact:(id)sender{
ABNewPersonViewController *picker = [[ABNewPersonViewController alloc] init];
UINavigationController *navigation = [[UINavigationController alloc] initWithRootViewController:picker];
[self presentModalViewController:navigation animated:YES];
[picker release];
[navigation release];
}
It pops up new contact view but when I click Cancel or Done button nothing happens.
Can anyone help me?
Thanks in advance!
//Make sure your VC is an <ABNewPersonViewControllerDelegate>
-(void) newPersonViewController:(ABNewPersonViewController *)newPersonView
didCompleteWithNewPerson:(ABRecordRef)person {
if (person != nil) //nil = Cancel button clicked
{
//do something
}
//iOS6
[self dismissViewControllerAnimated:YES completion:nil];
}
You need to add methods that should be called when the cancel or done button is tapped and that method should call [self.navigationController dismissModalViewController
This is the code I'm using to call the people picker, but the prompt label text doesn't change:
ABPeoplePickerNavigationController *picker = [[ABPeoplePickerNavigationController alloc] init];
picker.peoplePickerDelegate = self;
picker.displayedProperties = [NSArray arrayWithObjects: [NSNumber numberWithInt:kABPersonEmailProperty], nil];
picker.navigationItem.prompt = #"Choose a contact to...";
[self presentModalViewController:picker animated:YES];
There is a key piece of information missing in the other answers, and not quite obvious. You need to set the prompt after the line:
[self presentModalViewController:picker animated:YES];
So, if you do it like this, it works:
[self presentModalViewController:picker animated:YES];
picker.navigationBar.topItem.prompt = #"Choose a contact to...";
You can change the title with:
picker.navigationBar.topItem.title = #"iPhone Contacts";
And you can change the prompt with:
picker.navigationBar.topItem.prompt = #"iPhone Contacts";
I've just stumbled upon a way to do this. However, I'm not sure it's the best way. Just replace in the code above the line
picker.navigationItem.prompt = #"Choose a contact to...";
With
picker.navigationBar.topItem.prompt = #"Choose a contact to...";
If you're sub-classing the ABPeoplePickerNavigationController you need to set this once the view controller is pushed. This is in effect what achieving the same thing that Johan suggested, but from within the class.
In the ABPeoplePickerNavigationController implement the following delegate method like so:
-(void)navigationController:(UINavigationController *)navigationController
willShowViewController:(UIViewController *)viewController
animated:(BOOL)animated
{
[[[self navigationBar] topItem] setPrompt:#"test"];
}
I have an iPhone app that uses an action sheet but I can't work out how to make one of the buttons open a new view when pressed. I know how to implement the action sheet - that's not a problem, its the actual action of opening the new view that's the issue.
Any help would be greatly appreciated. Thanks.
I usually just create a new method and have the action sheet do it.
For instance:
switch (buttonIndex) {
case 0:
[self openModalView];
break;
}
Then, in your openModalView method:
- (void)openModalView {
MyModalViewController *myController = [[MyModalViewController alloc] init];
[self presentModalViewController:myController animated:YES];
[myController release];
}
In the UIAlertView's -didDismissWithButtonIndex, instantiate your new view controller and push it onto the navigation stack:
- (void)alertView:(UIAlertView *)alertView
didDismissWithButtonIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 0)
{
NewViewController *controller = [[NewViewController alloc] init];
[[self navigationController] pushViewController:controller animated:YES];
[controller release], controller = nil;
}
}