The keyboard that comes up with MFMailComposeViewController does not have any means to dismiss the keyboard once it comes up.
Does anyone have an idea of changing the keyboard. There are no UITextField exposed as you are actually in mail client at the time.
The mail composer isn't yours to modify, it is a system provided view controller which you are explicitly told not to modify in the docs:
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.
The cancel button is already there in the top left, what would "Done" do? Send the email? That's in the top right.
The MFMailComposeViewController doesn't have a "Done" button, because it assumes you will use that button as a return key (to make a new line).
If you really wanted to change the button to a "done" button, there is only one way I can think to do it:
Create a new MFMailComposeViewController.
Enumerate through [[mailComposer view] subviews].
Inspect each subview (and subviews of subviews, if required).
When you've found the UITextView that is the body, do the following:
// Get the UITextView from subview inspection
UITextView *textView;
// Declare this instance variable in your class #interface
id <UITextViewDelegate> originalTextViewDelegate;
// Get the original delegate
originalTextViewDelegate = [textView delegate];
// Override the delegate
[textView setDelegate:self];
// Set the return key type
[textView setReturnKeyType:UIReturnKeyDone];
Return YES on -textViewShouldEndEditing. Implement ALL UITextViewDelegate methods, and call originalTextViewDelegate (kind of like calling "super" on a subclass).
- (BOOL)textViewShouldEndEditing:(UITextView *)textView
{
[originalTextViewDelegate textViewShouldEndEditing:textView];
// Important: return YES, regardless of originalTextViewDelegate's response
return YES;
}
- (void)textViewDidChangeSelection:(UITextView *)textView
{
[originalTextViewDelegate textViewDidChangeSelection:textView];
}
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
return [originalTextViewDelegate textView:textView shouldChangeTextInRange:range replacementText:text];
}
// etc
That should work, but no guarantees. Hope that helps! :D
Related
I have a UIView which draws a signature. The signature is inputed via a custom inputView on the signature view.
When drawing the signature view, I use the fact that it's the first responder to highlight the view as being edited, and I also override the resignFirstResponder method to work out when to stop showing it as being edited.
So the code looks something like this:
#implementation SignatureView
-(BOOL) becomeFirstResponder {
BOOL result = [super becomeFirstResponder];
[self showEditingMode];
return result;
}
-(BOOL) resignFirstResponder {
BOOL result = [super resignFirstResponder];
[self showViewingMode];
return result;
}
-(UIView *) inputView {
if (!keyboard)
keyboard = [[SignatureKeyboardView alloc] initWithStuff:stuff....];
return keyboard;
}
#end
The problem I'm having is that on iOS 11, the resignFirstResponder method is no longer getting called. On previous versions of iOS, it used to get called and I could then change the UI to show that it's no longer being edited.
This ONLY HAPPENS when the UIScrollView is set to dismiss the keyboard when dragged, and the user drags the UIScrollView.
If the user instead taps another UIView that can become a first responder e.g. a UITextField, then resignFirstResponder gets called.
Am I missing something that changed in iOS11 or have I hit a bug?
I'd like to achieve the following behaviour of a single UITextField and the keyboard:
when the view has loaded UITextField becomes first responder and the keyboard opens (so far so good):
- (void)viewDidLoad
{
[self.editField becomeFirstResponder];
self.editField.delegate = self;
}
Now user inputs some text and presses the return key. That text is added to the data source in the following method:
- (IBAction)didEndOnExit:(id)sender {
//add self.editField.text to data source
}
Now after the return key is pressed and the above UITextField's method gets called and executed I would like the UITextField to clear, the cursor to be placed and be visible at the beginning of the text field and the keyboard not to hide so that new item could be entered in the textfield and added to the data source.
This is how I return to the previous view in the app (using a button):
- (IBAction)backButtonPressed:(id)sender {
[self dismissViewControllerAnimated:NO completion:^{}];
}
I tried playing with UITextFieldDelegate's methods and UITextField's becomeFirstResponder and resign FirstResponder, but am unable to achieve the above described behaviour. I've seen posts here on Stack Overflow about using consecutive UITextField's to enter data, but not to use the same UITextField time and again.
You should override the below mentioned method and do whatever you want and showing the keyboard too.
- (BOOL)textFieldShouldReturn:(UITextField *)textField
Have a try :)
While dismissing view controller all other code executions freezes when (view controller is being dismissed).
Use some delay (performselectorafterdelay). or
completionhandler of dismissingviewcontroller for executing your code when viewcontroller is being dismissing and
Also execute code on main Thread which includes UI changes or updates
after saved your data.. you have to make the uitextfield to be nil... like self.editField.text = nil. then you can call [self.editfield becomesfirstresponder].. after you will add more items to array or else anything everytime the field should be nil after you added..
From the Doc
Return Value: YES if the text field should implement its default
behavior for the return button; otherwise, NO.
For EX - Use the Delegate of UITextField :
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
//add self.editField.text to data source
textField.text = #"";
return NO; // This will do your need
}
Because I used UITextField's action method - (IBAction)didEndOnExit:(id)sender the keyboard always got closed. Apparently that method makes the UITextField resign from being first responder. Instead of adding data to data source in that method, it can be added in the delegates's method - (BOOL)textFieldShouldReturn:(UITextField *)textField and so the keyboard won't close.
How would I be able to make the keyboard appear automatically when the viewDidLoad? I also do not want to use the UITextField to make the keyboard appear.
Add a UITextField to your view and call it [myTextfield becomeFirstResponder]; Then set it to hidden myTextfield.hidden = true - so the user will never see the textfield.
You can do it by:
subclassing UIView (which is a subclass of UIResponder)
make your UIView Subclas conform to protocol UIKeyInput. To do this add
< UIKeyInput >
in the class declaration and this code to .m file
Add this code:
-(BOOL)hasText;
{
return YES;
}
-(void)insertText:(NSString *)text;
{
// what to do when a text is inserted
}
-(void)deleteBackward;
{
// what to do when delete is pressed
}
-(BOOL)canBecomeFirstResponder
{
// return yes if your control can become first responder and show the keyboard
return YES;
}
create a new instance of this custom view and add it as a subview of the current window (otherwise it won't work)
then, to show the keyboard, you have to simply call [myView becomeFirstResponder];
Just tried and it works well.
Edit: haven't tried, but it should work subclassing not only uiview, but all kind of objects that are subclasses of UIView and that can be added in the window hierarchy, simply it must conform UIKeyInput protocol
The only way I know without an UITextField is creating and adding an instance of the (private, undocumented) UIKeyBoard class. You can find an implementation here, in the showKeyboard:animated: method.
I'm trying to get rid of the keyboard when the user touch outside my UITextField, by using this method:
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[mainTextController resignFirstResponder];
[super touchesBegan:touches withEvent:event];
}
However, this seems to call a method that is called after pressing the return button on the keyboard, but I just want the keyboard to vanish, not to press return for me.
How can I accomplish that?
Thanks!
EDIT: tGilani's answer is the most straight-forward way, works like a charm, without changing to UIControl. But I guess jonkroll's answer also works.
try
[self.view endEditing:YES];
Update:
Take a boolean value and set it to false in init method. In your textFieldShouldReturn delegate method method, execute the code if it is false, skip otherwise
- (BOOL) textFieldShouldReturn:(UITextField*)textField
{
if (!boolean)
{
// YOur code logic here
}
boolean = false;
}
in your method where you call the endEditing method, set boolean to true.
boolean = YES;
[self.view endEditing:YES];
Here's how I've handled this before. First create a method on your view controller that will dismiss the keyboard by resigning first responder status on your text field:
- (IBAction)dismissKeyboard:(id)sender
{
[mainTextController resignFirstResponder];
}
Next, in your storyboard scene for your ViewController (or nib, if you are not using storyboards) change the class of your ViewController's view property from UIView to UIControl. The view property is effectively the background behind your other UI elements. The class type needs to be changed because UIView cannot respond to touch events, but UIControl (which is a direct subclass of UIView) can respond to them.
Finally, in your ViewController's viewDidLoad: method, tell your view controller to execute your dismissKeyboard method when the view receives a UIControlEventTouchDown event.
- (void)viewDidLoad
{
[super viewDidLoad];
UIControl *viewControl = (UIControl*)self.view;
[viewControl addTarget:self action:#selector(dismissKeyboard:) forControlEvents:UIControlEventTouchDown];
}
EDIT:
Part of your concern seems to be that textFieldDidEndEditing: is called when the keyboard is dismissed. That is unavoidable, it will always be called whenever a text field loses focus (i.e. first responder status). It sounds like your problem is that you have put code to perform when the user clicks the return button in textFieldDidEndEditing:. If you do not want that code to run when the user touches outside of the text field, that is not the proper place to put it.
Instead, I would put that code in a separate method:
- (IBAction)textFieldReturn:(id)sender
{
if ([mainTextController isFirstResponder]) {
[mainTextController resignFirstResponder];
// put code to run after return key pressed here...
}
}
}
and then call that method via Target-Action when your text field sends the control event UIControlEventEditingDidEndOnExit.
[mainTextController addTarget:self action:#selector(textFieldReturn:) forControlEvents:UIControlEventEditingDidEndOnExit];
Note that UIControlEventEditingDidEndOnExit is different than UIControlEventEditingDidEnd. The former is called when editing ends by the user touching outside the control, the latter is called when editing ends by the user pressing the return key.
You need to change your ViewController's view property from UIView to UIControl using the Identity Inspector:
From there, you simply create an IBAction and tell the textfield to dismiss (which I am assuming is your mainTextController). If mainTextController is not the textfield you want the keyboard to dismiss on then change the resignFirstReaponder method to your textfield like so.
- (IBAction)backgroundTap:(id)sender {
[myTextField resignFirstResponder];
}
then from there go back into your View Contoller's .xib file and connect the action to the Control View and select "Touch Down".
I've just started with xcode and objective-c and did some very basic apps, but what i'm having problem with is very basic this. the keyboard return button not hiding the keyboard.
I've searched the internet for the solution and all they say is to connect delegate to the file's owner and add the function and it should work, i did that and nothing is working.
I have an ok button and it is working and also clicking on any free space on the screen is working, just the return button....
I am using the simulator, not testing on iphone yet. (xcode 3.2.5 64 bit with the 4.2 simulator).
This is the line of code that should connect the delegate to every textFiled.
1. i've tried already to return both YES and NO, didn't work.
2. i've tried both a specific object name for the textField and this general way, didn't work.
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return NO;
}
In the: basic view controller connection -> connections -> outlets, i have the: delegate -- File's Owner. and in the file's owner in referencing outlets there is: delegate - Round style text.....
EDIT - i forgot to mention before, i've check and the method isn't being called!!!
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
NSLog(#"Working!!!");
[textField resignFirstResponder];
return YES;
}
what should i do to make it happen? that is why people say to connect the delegate, but in my case it is connected and not triggering the function...i know it is kind of dumb question but for a nobie like me the solution is not obvious...
OK, another Edit - with all my code: just can't understand what to do....
This is: basicViewController.h:
#import <UIKit/UIKit.h>
#interface basicViewController : <#superclass#> <UITextFieldDelegate>
#interface basicViewController : UIViewController <UITextFieldDelegate> {
//every object that we want to interact with (like text field or lable) is call an outlet!!!!
//here we define the outlets for our program
IBOutlet UITextField *txtName;
IBOutlet UILabel *lblMessage;
}
//here are the getters and setter for our outlets
#property (nonatomic, retain) IBOutlet UITextField *txtName;
#property (nonatomic, retain) IBOutlet UILabel *lblMessage;
//method decleration for the OK button action
- (IBAction) doSomething;
//method for hiding the keyboard when clicking on empty area in the app
//we will put an invisible button on all area and clicking on it will make keyboard disapear
- (IBAction) makeKeyboardGoAway;
#end
This is basicViewController.m:
#import "basicViewController.h"
#implementation basicViewController
//synthesizeing the objects that we made' this will create the getter and setters automaticly
#synthesize txtName;
#synthesize lblMessage;
- (IBAction) doSomething{
// makeing keyboard disapear when pressing ok button (doing that form the text field)
//when pressing the OK button, the keyboard will disapear and when clicking in the text field it will show again
[txtName resignFirstResponder];
NSString *msg = [[NSString alloc] initWithFormat:#"Hello, %#",txtName.text];
//the objective-c way for setting the test in the text field
[lblMessage setText:msg];
//the regular object oriented way
//lblMessage.text = msg;
[msg release];
}
- (IBAction) makeKeyboardGoAway{
[txtName resignFirstResponder];
}
//when clicking the return button in the keybaord
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
NSLog(#"Working!!!");
[textField resignFirstResponder];
return YES;
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
}
#end
Maybe now i am more clear, sorry i didn't do it before.
Any one has an idea what am i doing wrong? it should be pretty strait forward.....
EDIT - Adding an image of all the elements, i hope that will help to help me :-)
10x a lot for every one that is trying to help....i really like this framework, it is so great after c++ and java, python and many other...and i am working with a book, but it is for ios 3.1, maybe that is the problem.....
Firstly you should check if textFieldShouldReturn: is actually being called by adding an NSLog statement or breakpoint at the beginning of the method.
Once that's out of the way, try an manually declare that your view controller conforms to <UITextFieldDelegate> protocol in your interface file:
#interface YourClass : ... <UITextFieldDelegate>
Also declare a property & outlet for your UITextField, make the appropriate connections in IB and manually declare self as the UITextField delegate with:
self.yourUITextFieldObject.delegate = self;
Once that's done see if your method above is now being called and make sure you return YES.
Just write one line in the
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
}
before return YES;
the final version will be as given below:
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
return YES;
}
-(void)textFieldDidEndEditing:(UITextField *)textField{
NSLog(#"%#",textField.text);
}
You need to assign the delegate of the textfields to your file owner. The textfields are sending the message, but doesn't have a delegate to respond to it.
Use the interface builder to do that.
You have to implement this method..
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
Like Rog said, don't forget to register the textfield to the delegate, you can do this manually as he said but in Storyboard you can just control drag from all of your textfields to the view controller and register the delegate (choose delegate). Only the textfields that are registered can make use of all those methods.
So this line is important:
self.yourUITextFieldObject.delegate = self;
Or even more easy these days is to just use the storyboard:
textfield is in a subview? in this case, make sure textfield have as delegate the FileOwner.
put a log at the
- (IBAction) makeKeyboardGoAway
function. I think its this method everytime anything is tapped on the screen. In that case, you will need to send the touch event to the text field. Not sure how this is done but that should do it.
Else try removing the which takes care of tap(click) all over the view and try to do what you are doing.
Most likely the problem is that your actual view controller in the running application is not a "basicViewController" but a UIViewController that does not implement the UITextFieldDelegate-protocol.
What you've done in the interface builder by selecting your class "basicViewController" as the FilesOwner is just declaring the FilesOwner-object in your running application to be of type basicViewController; the actual object is not instantiated by this declaration and in your case it is not in the xib / nib.
Some other part of your code actually instantiates a view controller object and loads the xib / nib file. At that place, I guess your code is instantiating a UIViewController (typically by auto-generated code) and not an instance of your basicViewController; you simply have to change the class there.
Furthermore, this error often happens when using a UINavigationController or UITabBarController in the Interface Builder that is (should be) configured to instantiate and load other custom views. If you use such a higher-level controller, double-check that it is actually configured to use your basicViewController, not UIViewController when loading your view from the xib / nib.
Hope, that solves the issue!
Can you try this..
#interface ClassName : SuperClass < UITextFieldDelegate >
Use like this...
textfield.delegate=self;
and use the UITextFieldDelegate in .h class
You can always dismiss the keyboard when you don’t even know which view the text field is in by using:
Objective-C:
[[UIApplication sharedApplication] sendAction:#selector(resignFirstResponder)
to:nil
from:nil
forEvent:nil];
Swift:
UIApplication.sharedApplication().sendAction("resignFirstResponder",
to:nil,
from:nil,
forEvent:nil)