Im working on an app which allows the user to select a contact from phone's address book and displays that contact in the UITableView. Im using following code to pick up the contact;
-(IBAction)pickPhoneContacts:(id)sender //opens phone's address book
{
ABPeoplePickerNavigationController *picker =
[[ABPeoplePickerNavigationController alloc] init];
picker.peoplePickerDelegate = self;
[self presentViewController:picker animated:YES completion:nil];
}
//called when user presses the cancel button in the Address book view controller
- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController*)peoplePicker
{
[self dismissViewControllerAnimated:YES completion:nil];
}
//called when user pics up a contact from the phone's address book
- (BOOL)peoplePickerNavigationController:
(ABPeoplePickerNavigationController *)peoplePicker
shouldContinueAfterSelectingPerson:(ABRecordRef)person {
[self displayPerson:person]; //calls displayPerson:(ABRecordRef)person to show contact's information in the app
[self dismissViewControllerAnimated:YES completion:NULL];
return NO;
}
//called when the user selects the property of the contact. This method will not be called in the app but included to complete the implementation of the protocol
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)
peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person
property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier
{
return NO;
}
//Displays the contact name and the contact's primary number in the app's text fields (add contact view controller)
- (void)displayPerson:(ABRecordRef)person
{
NSString* name = (__bridge_transferNSString*)ABRecordCopyValue(person,kABPersonFirstNameProperty); //Extracts the contact's first name from address book & assigns it to a string value
self.contactNameTextFiled.text = name;
NSString* phone = nil;
//Extracts the first phone number among multiple contact numbers from address book & assigns it to a string value
ABMultiValueRef phoneNumbers = ABRecordCopyValue(person,kABPersonPhoneProperty);
if (ABMultiValueGetCount(phoneNumbers) > 0)
{
phone = (__bridge_transfer NSString*)
ABMultiValueCopyValueAtIndex(phoneNumbers, 0);
}
else
{
phone = #"[None]";
}
self.primaryNumberTextField.text = phone;
CFRelease(phoneNumbers);
}
Now the task is, as soon as the user pics up a contact from the address book, the ABPeoplePickerNavigator should dismiss and immediately MFMessageComposeViewController should present with a default message and the picked contact number. So that the user of the app should send a message to the picked contact number. I have used following code for message compose view controller;
-(void)sendSMS
{
MFMessageComposeViewController *controller = [[MFMessageComposeViewController alloc] init];
if([MFMessageComposeViewController canSendText])
{
controller.body = #"Test Message";
controller.recipients = [NSArray arrayWithObjects:#"111222333", nil];
controller.messageComposeDelegate = self;
[self presentViewController:controller animated:YES completion:nil];
}
}
Now please help me where should I call this method so that the MFMessageComposeViewController should present as soon as the ABPeoplePickerNavigationController dismiss.
Use new function dismissViewControllerAnimated: completion: so after completion call send sms as i have edited your code.
- (BOOL)peoplePickerNavigationController:
(ABPeoplePickerNavigationController *)peoplePicker
shouldContinueAfterSelectingPerson:(ABRecordRef)person {
[self displayPerson:person]; //calls displayPerson:(ABRecordRef)person to show contact's information in the app
// [self dismissViewControllerAnimated:YES completion:NULL];
[self dismissViewControllerAnimated:YES completion:^{
[self sendSMS];
}];
return NO;
}
Set animation of your adresscontroller to No when you are dismissing it
[self dismissViewControllerAnimated:NO completion:nil];
Try in
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person;
call
-(void)sendSMS
in dismissViewControllerAnimated:completion: completion handler.
[self dismissViewControllerAnimated:YES completion:{[self sendSMS]}];
Hopes this helps.
in .h file
MFMessageComposeViewController *controller ;
ABPeoplePickerNavigationController *picker;
and in .m just do this
in -(void)sendSMS
{
//other code
[picker presentViewController:controller animated:YES completion:nil];
}
Related
When I try to show the facebook share after having sent an email (using MFMailComposeViewController) I get this error:
A view can only be associated with at most one view controller at a
time! View [EAGLView] is associated with [EmailViewController]. Clear
this association before associating this view with [FacebookView].'
[EmailViewController removeFromParentViewController]; Does nothing
EmailViewController.view = nil; Causes a white screen, even though the email form is long gone.
How to make it forget that I ever sent and email and make the view hierarchy go back to how it was before? The facebook share works if I haven't sent an email.
-(IBAction)ShowEmailForm:(char*)pSubject :(char*)pBody :(char*)pTo
{
Class mailClass = (NSClassFromString(#"MFMailComposeViewController"));
if (mailClass != nil)
{
if ([mailClass canSendMail])
{
self.view = eaglView;
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;
[picker setSubject:[NSString stringWithFormat:#"%s", pSubject]];
// Set up recipients
if( pTo != nil )
{
NSArray *toRecipients = [NSArray arrayWithObject:[NSString stringWithFormat:#"%s", pTo]];
[picker setToRecipients:toRecipients];
}
// Fill out the email body text
[picker setMessageBody:[NSString stringWithFormat:#"%s",pBody] isHTML:YES];
[self presentViewController:picker animated:YES completion:^(){}];
[picker release];
}
}
}
// Dismisses the email composition interface when users tap Cancel or Send. Proceeds to update the message field with the result of the operation.
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
[self dismissViewControllerAnimated:YES completion:^(){ printf("Email form done dismissing.\n"); }];
printf("Email form dismissed.\n");
[self removeFromParentViewController];
//Email was sent.
if (result == MFMailComposeResultSent)
{
printf("Email Sent!\n");
NSString *pEmail = [self findEmailAddresses:controller.view : 0];
}
}
Fixed it.
Change
self.view = eaglView;
to
[eaglView addSubview:self.view];
In my iPhone application, I have just implemented in-app SMS functionality. SMS functionality is working fine. But after opening MFMessageComposeViewController, if user wants to cancel sending sms, they have no option. The only option left is to send an sms, then only return on previous view. There should be a cancel button on navigation bar just as it is in the email composer. Below is the line of code that I wrote to have in-app sms functionality:
-(void) smsComposer{
MFMessageComposeViewController *_smsCompose = [[MFMessageComposeViewController alloc] init];
if ([MFMessageComposeViewController canSendText]) {
_smsCompose.body = #"SMS BODY";
_smsCompose.messageComposeDelegate = self;
[self presentModalViewController:_smsCompose animated:YES];
}
}
Is there anything that I am missing?
Thanks in advance,
PC
Try This....
in .h file
#import <MessageUI/MFMessageComposeViewController.h>
and
#interface TestViewController : UIViewController <MFMessageComposeViewControllerDelegate>
And then Button Click method
-(void)buttonPressed:(UIButton *)button
{
[self sendSMS:#"Body of SMS..." recipientList:[NSArray arrayWithObjects:#"+1-111-222-3333", #"111-333-4444", nil]];
}
MFMessageComposeViewController to create the SMS content and another method for handling the user interaction with the SMS dialog.
-(void)sendSMS:(NSString *)bodyOfMessage recipientList:(NSArray *)recipients
{
MFMessageComposeViewController *controller = [[[MFMessageComposeViewController alloc] init] autorelease];
if([MFMessageComposeViewController canSendText])
{
controller.body = bodyOfMessage;
controller.recipients = recipients;
controller.messageComposeDelegate = self;
[self presentModalViewController:controller animated:YES];
}
}
And
-(void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result
{
[self dismissModalViewControllerAnimated:YES];
if (result == MessageComposeResultCancelled)
NSLog(#"Message cancelled")
else if (result == MessageComposeResultSent)
NSLog(#"Message sent")
else
NSLog(#"Message failed")
}
And remember: You cannot send SMS messages from within the simulator. Test on Device.
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
I'm trying to implement a view similar to contacts view in iPhone Message (SMS) app.
When composing a message on iPhone, there will be "+" button to add contacts. On click of "+", it will show list of contacts and just by selecting a contact, it will add the contact name in "To" text field.
I found following code to show contacts. But on click of a contact, its showing more details about the contact and just not selected.
ABPeoplePickerNavigationController* picker;
picker = [[ABPeoplePickerNavigationController alloc] init];
picker.peoplePickerDelegate = self;
CGRect newFrame = picker.view.frame;
newFrame.size.height = newFrame.size.height - 49;
picker.view.frame = newFrame;
[self presentModalViewController:picker animated:NO];
[picker release];
Can some body point out me correct way to select a contact?
I found the solution.
I've to implement the delegate methods to handle that.
The following are the delegate methods
- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker {
[self dismissModalViewControllerAnimated:YES];
}
- (BOOL)peoplePickerNavigationController: (ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person
{
.
.
.
.
[self dismissModalViewControllerAnimated:YES];
return NO;
}
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person
property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier
{
return NO;
}
I'm near desperation as I search for a solution for weeks now.
The Problem is simple:
Via the ABPeoplePickerNavigationController (as a ModalView), a person should be selected.
Then only (e.g.) the Mail addresses should be shown and the user should select one.
After selection of a Mail address just the (e.g.) phone numbers should be shown and the user should select one.
The solution until the third aspect is well-known:
- (IBAction)importFromAddressBook
{
ABPeoplePickerNavigationController* picker = [[ABPeoplePickerNavigationController alloc] init];
picker.peoplePickerDelegate = self;
[self presentModalViewController:picker animated:YES];
[picker release];
}
- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker
{
[self dismissModalViewControllerAnimated:YES];
}
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController*)peoplePicker
shouldContinueAfterSelectingPerson:(ABRecordRef)person
{
[peoplePicker setDisplayedProperties:[NSArray arrayWithObject:[NSNumber numberWithInt:kABPersonEmailProperty]]];
return YES;
}
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker
shouldContinueAfterSelectingPerson:(ABRecordRef)person
property:(ABPropertyID)property
identifier:(ABMultiValueIdentifier)identifier
{
//===PROBLEM=== Now I do have a mail address and I want to have a phone number right afterwards.
//Something like this would be straightforward, but the view does not change this way:
[peoplePicker setDisplayedProperties:[NSArray arrayWithObject:[NSNumber numberWithInt:kABPersonPhoneProperty]]];
//Here misses the important code.
//And only when I also got a phone number through this or a similar method I want to call:
[peoplePicker dismissModalViewControllerAnimated:YES];
//I do not want to start default behaviour with the mailaddress and/or phone number:
return NO;
}
The right approach seems to push a similar peoplePicker View on the NavigationController of the ModalView, but I don't know how.
If anyone had any idea it would be great!
If you want to see such a behavior in action you can have a look at the Amazon app: If you go through the first steps of an order you can select a shipping address exactly this way: From Contact List -> Select a Person -> Select an Address -> Select a Telephone number.
There, everything (seems to) take place in the modal view with just a navigation hierarchy with one more level than in the standard code shown above.
I guess this might be what you want:
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker
shouldContinueAfterSelectingPerson:(ABRecordRef)person
property:(ABPropertyID)property
identifier:(ABMultiValueIdentifier)identifier
{
ABPersonViewController *controller = [[ABPersonViewController alloc] init];
controller.displayedPerson = person;
controller.displayedProperties = [NSArray arrayWithObject:[NSNumber numberWithInt:kABPersonPhoneProperty]];
controller.personViewDelegate = self;
[peoplePicker pushViewController:controller animated:YES];
[controller release];
return NO;
}
- (BOOL)personViewController:(ABPersonViewController *)personViewController
shouldPerformDefaultActionForPerson:(ABRecordRef)person
property:(ABPropertyID)property
identifier:(ABMultiValueIdentifier)identifierForValue
{
ABMutableMultiValueRef multi = ABRecordCopyValue(person, property);
CFStringRef phone = ABMultiValueCopyValueAtIndex(multi, identifierForValue);
NSLog(#"phone %#", (NSString *)phone);
CFRelease(phone);
ABPeoplePickerNavigationController *peoplePicker = (ABPeoplePickerNavigationController *)personViewController.navigationController;
[peoplePicker dismissModalViewControllerAnimated:YES];
return NO;
}
The idea is, to create another ABPersonViewController instance, and let your people picker to push it, since ABPeoplePickerNavigationController is a subclass of NSPeoplePickerNavigationController.
In the suggested answer there is a release missing
CFRelease(multi);
Without this release a leak will occur. Or at least according to the Build and Analyze in Xcode....
The following method should return NO:
- (BOOL)peoplePickerNavigationController:
(ABPeoplePickerNavigationController*)peoplePicker
shouldContinueAfterSelectingPerson:(ABRecordRef)person
{
...
return NO;
}
This will allow your next method be called (peoplePickerNavigationController:shouldContinueAfterSelectingPerson:property:identifier:).
In my iPhone app Pastie, I took a different approach.
(source: manicwave.com)
I use the peoplePicker to select the person and then open a contact (person) editor.
This is just a simple view:
Contact Name
Phone Number > defaults to first phone number
email Address > defaults to first email address
Each of phone number and email address bring up another view showing the list of phones or email addresses, with a check mark next to the currently selected one.
I use this view for initial setup of a contact as well as subsequent editing.