Set First Responder in MFMailComposeViewController?
Asked Answered
I

4

6

I'm using Apple's MailComposer example application to send email from within my application (OS 3.0 functionality). Is it possible to set the To, Subject, or Body fields as first responder with MFMailComposeViewController?

In other words, the behavior would be: the user presses a button which presents the mail view (presentModalViewController). When the mail view is presented, the cursor is placed in one of the fields and the keyboard opens.

I notice the MFMailComposeViewController documentation says:

"Important: The mail composition interface itself is not customizable and must not be modified by your application. In addition, after presenting the interface, your application is not allowed to make further changes to the email content. The user may still edit the content using the interface, but programmatic changes are ignored. Thus, you must set the values of content fields before presenting the interface."

However, I don't care about customizing the interface. I just want to set that firstResponder. Any ideas?

Interconnect answered 6/11, 2009 at 20:42 Comment(0)
P
8

You are able to make these fields become the first responder.

if you add the following method to your class...

//Returns true if the ToAddress field was found any of the sub views and made first responder
//passing in @"MFComposeSubjectView"     as the value for field makes the subject become first responder 
//passing in @"MFComposeTextContentView" as the value for field makes the body become first responder 
//passing in @"RecipientTextField"       as the value for field makes the to address field become first responder 
- (BOOL) setMFMailFieldAsFirstResponder:(UIView*)view mfMailField:(NSString*)field{
    for (UIView *subview in view.subviews) {

        NSString *className = [NSString stringWithFormat:@"%@", [subview class]];
        if ([className isEqualToString:field])
        {
            //Found the sub view we need to set as first responder
            [subview becomeFirstResponder];
            return YES;
        }

        if ([subview.subviews count] > 0) {
            if ([self setMFMailFieldAsFirstResponder:subview mfMailField:field]){
                //Field was found and made first responder in a subview
                return YES;
            }
        }
    }

    //field not found in this view.
    return NO;
}

Then, after you present the MFMailComposeViewController, pass the MFMailComposeViewController's view into the function along with the field you want to become first responder.

MFMailComposeViewController *mailComposer = [[MFMailComposeViewController alloc] init];
mailComposer.mailComposeDelegate = self;

/*Set up the mail composer*/

[self presentModalViewController:mailComposer animated:YES];
[self setMFMailFieldAsFirstResponder:mailComposer.view mfMailField:@"RecipientTextField"];
[mailComposer release];
Peele answered 13/7, 2010 at 1:42 Comment(6)
Excellent - spent hours trying to find something to do this. Just needed to change RecipientTextField to MFRecipientTextField to work. Is this OK to use for App Store submissions, or deemed to be undocumented API?Jonellejones
I am unsure if this is ok to use for App Store submissions, I have only used this for in house applications.Peele
Apple approved my app that used this recently, so looks like it's fine to use (at least for now!) Thanks again.Jonellejones
Hi, the above solution does not work for me, it is showing only UINavigationTransitionView,UILayoutContainerView,UIButtonLabel,UINavigationButton etc. as class names when I print them in the method. It is not giving a subview class called MFRecipientTextField etc. Any idea whats wrong?Pict
BTW, the recipient view is 'MFMailComposeRecipientView' not 'RecipientTextField', at least for me.Lot
I believe this technique no longer works in iOS 6 due to the use of remote view controllers. I'd love to hear about an updated approach to making this happen.Continuance
W
4

In iOS 6, it is no longer possible to set first responder on any of the text fields AFAICT. Navigating the view hierarchy eventually reveals a UIRemoteView and the subviews within here are obfuscated away.

Wilhoit answered 9/3, 2013 at 14:23 Comment(0)
W
1

You can try just calling becomeFirstResponder on the controller itself. If that doesn't work, you can try in the debugger getting the list of subviews of the mail compose view until you find a familiar textfield or textview which you can then code specifically to set the responder status in code, which might look something like this (i don't know if this will work but it's an example):

[[[[mailcomposer.view.subviews objectAtIndex:3] subviews] objectAtIndex:2] becomeFirstResponder]
Wildeyed answered 12/2, 2010 at 17:3 Comment(0)
W
0

I like to simplify the code and make it easy to understand. Just put the follow code after:
[self presentModalViewController:mailComposer animated:YES];

for (UIView *subview in mailComposer.view.subviews) {
   NSString *className = [NSString stringWithFormat:@"%@", [subview class]];
   //NSLog(@"%@", className); // list the views - Use this to find another view
   //The view I want to set as first responder: "_MFMailRecipientTextField"
   if ([className isEqualToString:@"_MFMailRecipientTextField"]){
   [subview becomeFirstResponder];
   break; // Stop search.
  }
}
Wyatt answered 4/4, 2012 at 1:5 Comment(1)
This doesn't work as the recursion is necessary to navigate down the view hierarchy.Pizzicato

© 2022 - 2024 — McMap. All rights reserved.