textFieldDidBeginEditing: not getting called - ios

I got the code below from this SO question. I'm trying to slide up textfields when I begin editing (because they otherwise get covered by the iPhone keyboard). However, the log statement reveals that the textFieldDidBeginEditing method is not getting called.
I have the code below in two different subclasses of UIViewController. In one of them, for example, I have a textfield connected from the storyboard to the UIViewController like this
#property (strong, nonatomic) IBOutlet UITextField *mnemonicField;
I moved the textfield up to the top of the view (i.e. not covered by keyboard) so that I could edit it to try to trigger the log statement but it didn't work. The text field otherwise works as expected i.e. the data I enter is getting saved to coreData etc etc.
Can you explain what I might be doing wrong?
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
NSLog(#"The did begin edit method was called");
[self animateTextField: textField up: YES];
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
[self animateTextField: textField up: NO];
}
- (void) animateTextField: (UITextField*) textField up: (BOOL) up
{
const int movementDistance = 180; // tweak as needed
const float movementDuration = 0.3f; // tweak as needed
int movement = (up ? -movementDistance : movementDistance);
[UIView beginAnimations: #"anim" context: nil];
[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration: movementDuration];
self.view.frame = CGRectOffset(self.view.frame, 0, movement);
[UIView commitAnimations];
}

You have not assigned your delegate of UITextField in your ViewController class:
In your viewcontroller.m file, In ViewDidLoad method, do this:
self.mnemonicField.delegate=self;
In your viewcontroller.h file, do this:
#interface YourViewController : ViewController<UITextFieldDelegate>

You should set up text field delegate to self.
Add this line to viewDidLoad method:
self.mnemonicField.delegate = self;
and remember to add this line <UITextFieldDelegate> to conform to that protocol.
You can achieve the same effect in storyboard by control drag from desired UITextField to view controller and select delegate.

You created IBOutlet so just drag your textfield to viewController and set delegate
Then in .h add the following
#interface ViewController : ViewController<UITextFieldDelegate>

In other case if you click any other button without moving the focus of Uitextfield then delegate will not be called, for that you need to explicitly call
yourtextfield.resignFirstResponder()

Related

Keyboard is not hiding when click on second textField [duplicate]

This question already has an answer here:
Issue related to textfield and datepicker
(1 answer)
Closed 6 years ago.
I have two textFields. On click, the first one is showing a qwerty keyboard and the second one is showing picker.
My issue is when I'm clicking on my first textField, the keyboard is showing properly. Now, After I type anything, I directly want to click on the second textField which is the showing picker and the keyboard should disappear, but the keyboard is still there.
I want to hide the keyboard as soon as I click on the second textField.
There are two ways to achieve this -
First: Use the UITextFieldDelegate.
For that-
List the UITextFieldDelegate in your view Controller's protocol list like,
#interface ViewController : UIViewController <UITextFieldDelegate>
Then make your ViewController conform to the Textfield's delegate to implement the methods like textFieldDidBeginEditing, and textFieldDidEndEditing:
So, go to the viewDidLoad method and conform to the UITextField's protocol like-
- (void)viewDidLoad
{
[super viewDidLoad];
self.firstTextField.delegate = self; //assuming your first textfield's
//name is firstTextField
//Also give your first textfield a tag to identify later
self.firstTextField.tag = 1;
}
Now, you are set to implement the delegate methods. But, to achieve your target first, you need to take a UITextField instance to know when you are typing in the firstTextField. So, declare a property of UITextField type. Do that in the interface file like-
#property(nonatomic, strong) UITextField *currentTextField;
Now in the textFieldDidBeginEditing delegate method, assign the firstTextField instance to the currentTextField when you start typing in it like-
- (void)textFieldDidBeginEditing:(UITextField *)textField{
if(textField.tag == 1){
self.currentTextField = textField;
}
}
After that in the textFieldDidEndEditing method, check if it is the current textfield from which you are coming out and dismiss the keyboard like-
-(void)textFieldDidEndEditing:(UITextField *)textField{
if(textField.tag == 1){
[self.currentTextField resignFirstResponder];
}
return YES;
}
Second: You can use UIResponder. As ViewControllers inherit from UIResponder, you just override the method- touchesBegan:withEvent method, something like-
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[self.view endEditing:YES];// this will do the trick
}
In this case, when you click out side the textField, the keyboard should automatically disappear.
use UITextFieldDelegate set delegate to self in ViewDidLoad and then put this code
func textFieldDidEndEditing(textField: UITextField)
{
yourtextfieldname.resignFirstResponder()
return true
}
Step 1 :- Code for ViewController.h :-
//add UITextFieldDelegate just after UIViewController
#interface ViewController : UIViewController<UITextFieldDelegate>
Step 2 :- Code For ViewController.m :-
//inside viewdidLoad write following code, where txtInput is outlet for input text field
_txtInput.delegate = self;
// Last Thing write following code just above #end
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
//that's it use this very simple way

How can I make a UITextField the first responder, correctly? (Tried 3 methods)

Here's the setup:
SNController is an NSObject and it has inside:
UIView
UITextField
UISegmentedControl
UILabel
UIButton
The view is the same as the view inside the ViewController.
One can be visible at the time. When the UITextField is visible (alpha = 1.0)
all the others are invisible (alpha = 0.0).
(1) I perform an animation and I want the text field:
UITextField *textField;
to become the first responder while the animation happens:
[textField becomeFirstResponder];
[UIView animateWithDuration: ...];
Unfortunately it doesn't work.
I've logged the text field and it showed that it cannot become the first responder and I have no idea why...
I've tried another two methods but none of them worked so far:
(2) A complicated way to communicate with the ViewController from the SNController:
Inside the SNController.h/.m:
#property (nonatomic, copy) void(^eventCallBack)();
if (self.eventCallBack) {
self.eventCallBack();
}
Inside the ViewController.m:
__weak ViewController *self_ = self;
self.restoration.controller.eventCallBack = ^(){
[self_.restoration.controller.textField becomeFirstResponder];
};
(3) I also tried these methods from inside the SNController:
[self.textField performSelector:#selector(becomeFirstResponder) withObject:nil afterDelay:0.0];
[self.textField performSelectorOnMainThread:#selector(becomeFirstResponder) withObject:nil waitUntilDone:YES];
It just won't give up, it doesn't become the first responder no matter what.
Any ideas?
I realised there was a mistake. There isn't a UITextField inside the SNController but a UIView subclass named SNTextField.
I implemented this method where the UITextField was initialised:
- (void)activateKeyboard
{
[self.textField becomeFirstResponder];
}
and it worked!

Animating constraints causing subviews layout to be visible on screen

I have a messaging screen I am creating and I am almost done it. I built most of the views with nib files and constraints. I have one small bug however where I can visually see some of the cells laying themselves out when the keyboard dismisses because of the requirement to call [self.view layoutIfNeeded] in an animation block involving a constraint. Here is the problem:
- (void)keyboardWillHide:(NSNotification *)notification
{
NSNumber *duration = [[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey];
NSNumber *curve = [[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey];
[UIView animateWithDuration:duration.doubleValue delay:0 options:curve.integerValue animations:^{
_chatInputViewBottomSpaceConstraint.constant = 0;
// adding this line causes the bug but is required for the animation.
[self.view layoutIfNeeded];
} completion:0];
}
Is there any way around directly calling layout if needed on the view since this also causes my collection view to lay itself out which makes the cells layout visually on screen sometimes.
I tried everything I can think of but it I can't find a solution to the bug fix. I have already tried calling [cell setNeedLayout]; in every location possible, nothing happens.
How about this?
In your UITableViewCell implement a custom protocol called MYTableViewCellLayoutDelegate
#protocol MYTableViewCellLayoutDelegate <NSObject>
#required
- (BOOL)shouldLayoutTableViewCell:(MYTableViewCell *)cell;
#end
Create a delegate for this protocol
#property (nonatomic, weak) id layoutDelegate;
Then override layoutSubviews on your UITableViewCell:
- (void)layoutSubviews {
if([self.layoutDelegate shouldLayoutTableViewCell:self]) {
[super layoutSubviews];
}
}
Now, in your UIViewController you can implement the shouldLayoutTableViewCell: callback to control whether the UITableViewCell gets laid out or not.
-(void)shouldLayoutTableViewCell:(UITableViewCell *)cell {
return self.shouldLayoutCells;
}
Modify your keyboardWillHide method to disable cell layout, call layoutIfNeeded, and restore the cell layout ability in the completion block.
- (void)keyboardWillHide:(NSNotification *)notification {
NSNumber *duration = [[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey];
NSNumber *curve = [[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey];
self.shouldLayoutCells = NO;
[UIView animateWithDuration:duration.doubleValue delay:0 options:curve.integerValue animations:^{
_chatInputViewBottomSpaceConstraint.constant = 0;
[self.view layoutIfNeeded];
} completion:completion:^(BOOL finished) {
self.shouldLayoutCells = NO;
}];
}
I can't really test this since you didn't provide sample code, but hopefully this will put you on the right path.

How do I dismiss a keyboard after my user has entered the value for a text field?

I know this question has been asked a few times, but none of the answers have enough detail for me (me = n00b) to understand.
I have a simple little app that I put together via the storyboard, it has two text fields that the user can type into. I want the user to be able to dismiss the keyboard after they edit either field.
I know it has something to do with "resignFirstResponder" but I'm not sure where to put that.
Here is my top secret code
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize thing1;
#synthesize thing2;
// NSArray things = #[thing1, thing2];
// self.thingLabel.text = array[arc4random()%array.count];
- (IBAction)pick:(id)sender {
// create an empty list that will get filled with things
NSMutableArray *things = [NSMutableArray arrayWithObjects:thing1.text,thing2.text, nil];
NSString *theThing = things[arc4random()%things.count];
NSLog(#"the thing is %#", theThing);
}
#end
and here is my ViewController.h file:
//
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UITextFieldDelegate>
#property (weak, nonatomic) IBOutlet UITextField *thing1;
#property (weak, nonatomic) IBOutlet UITextField *thing2;
#end
Since your view controller adopts the UITextFieldDelegate protocol (i.e., <UITextFieldDelegate>), then the easiest technique is to have the view controller implement the following two methods:
// place in ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
// note that you could set the text field delegate in IB instead
self.thing1.delegate = self;
self.thing2.delegate = self;
}
// this method gets called by the system automatically when the user taps the keyboard's "Done" button
- (BOOL)textFieldShouldReturn:(UITextField *)theTextField
{
[theTextField resignFirstResponder];
return YES;
}
That's all the code you need. Now when the user taps the keyboard's "Done" button, the keyboard goes away.
You could just add a button beside the textfield and dismiss it when that one is pressed:
UIButton *doneEnteringButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[doneEnteringButton addTarget:addTarget:self action:#selector(dismissKeyboard:) forControlEvents:UIControlEventTouchUpInside];
- (void)dismissKeyboard
{
[self.view endEditing:YES];
}
This single button will dismiss the keyboard, no matter which textfield you are in. If you don't want the button a cool way would be to add a gesture recognizer to the parent view of the textfield and do endEditing:YES there.
Hope this helps! Ask if it doesn't
try this code, when user tap any where to dismiss keyboard
- (void)setupKeyboardDismiss{
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
UITapGestureRecognizer *singleTapGR =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(tapAnywhereToDismissKeyboard:)];
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
[nc addObserverForName:UIKeyboardWillShowNotification
object:nil
queue:mainQueue
usingBlock:^(NSNotification *note){
[self.view addGestureRecognizer:singleTapGR];
}];
[nc addObserverForName:UIKeyboardWillHideNotification
object:nil
queue:mainQueue
usingBlock:^(NSNotification *note){
[self.view removeGestureRecognizer:singleTapGR];
}];
}
- (void)tapAnywhereToDismissKeyboard:(UIGestureRecognizer *)gestureRecognizer{
[self.view endEditing:YES];
}
This depends on the UI & functionality you are trying to develop. You can do it in following ways:
Add a "Done" button to your UI for user to take an action once they are done with entering data in text fields and then in the action handler for that button call [yourTextField resignFirstResponder].
Add a custom keyboard down button to your keyboard.
Implement the below delegate methods on UITextField and put logic in them and call [yourTextField resignFirstResponder] once the required criterion is met. For example once user has entered certain number of characters it will auto-dismiss the keyboard.
When user is done and tap outside the textfield view, dismiss the keyboard. Implement 'touchesbegan' on UIView and let the viewcontroller about it.
-(BOOL)textField:(UITextField *)iTextField shouldChangeCharactersInRange:(NSRange)iRange replacementString:(NSString *)iString
-(void)textFieldDidEndEditing:(UITextField *)iTextField

UIView Flip Animation with Core Animation

Dear Core Animation/iOS Experts,
I am trying to get an effect similar to the question below.
Core animation animating the layer to flip horizontally
The accepted answer seems to describe exactly what I require, except there is no code with this answer and I can't get any code I write to work.
Here is exactly what I'm trying to do:
1) Have 1 master view controller/view and on a portion of the main view have 2 UIViews which overlap, with only one shown (1 at the 'front' and 1 at the 'back')
2) A separate UIControl/UIButton gets pressed and then a 3D flip transition occurs which rotates the front (visible) view out of view and at same time rotates the back (hidden) view to the front...just like seeing the reverse of a playing card.
3) Be able to keep pressing the UIControl to toggle between the two views
4) Be able to interact with just the controls on the front view (i.e. pressing the front layer won't inadvertently fire a control on the back which happens to lie underneath the tap)
I may be approaching this the wrong way so let me know. Ideally, I would like to use Core Animation, and not the UIView built in flip transactions, as I want the animation to be 3D and also want to use this task as a stepping stone for doing more complex CA stuff.
At the moment I can get the front view to flip nicely (only once) but the back view doesn't show.
Cheers,
Andy
Here is the code I've got:
MainViewController.h
#interface MainViewController : UIViewController
- (IBAction)changeViewTapped:(UITapGestureRecognizer *)recognizer;
#end
MainViewController.m
#import "MainViewController.h"
#import <QuartzCore/QuartzCore.h>
#interface MainViewController ()
#property (weak, nonatomic) IBOutlet UIView *detailView;
#property (weak, nonatomic) IBOutlet UIView *listView;
#property (nonatomic) CATransform3D rotationAndPerspectiveTransform;
#end
#implementation MainViewController
#synthesize detailView = _detailView;
#synthesize listView = _listView;
#synthesize rotationAndPerspectiveTransform = _rotationAndPerspectiveTransform;
- (void)viewDidLoad {
[super viewDidLoad];
CATransform3D rotationAndPerspectiveTransform = CATransform3DIdentity;
rotationAndPerspectiveTransform.m34 = 1.0 / -500;
rotationAndPerspectiveTransform = CATransform3DRotate(rotationAndPerspectiveTransform, M_PI, 0.0f, 1.0f, 0.0f);
self.rotationAndPerspectiveTransform = rotationAndPerspectiveTransform;
CALayer *listLayer = self.listView.layer;
listLayer.doubleSided = NO;
listLayer.transform = self.rotationAndPerspectiveTransform;
}
- (IBAction)changeViewTapped:(UITapGestureRecognizer *)recognizer {
CALayer *detailLayer = self.detailView.layer;
CALayer *listLayer = self.listView.layer;
detailLayer.doubleSided = NO;
listLayer.doubleSided = NO;
[UIView animateWithDuration:0.5 animations:^{
detailLayer.transform = self.rotationAndPerspectiveTransform;
listLayer.transform = self.rotationAndPerspectiveTransform;
} completion:^(BOOL finished){
// code to be executed when flip is completed
}];
}
#end
A quick tip about the flip animation in iOS -- the system needs time to render the back view (the one that will be flipped to) before you start the flip animation. So if you try to change the contents of that view, and trigger off the flip animation in the same method, you will have problems.
To get around this, I've had success with code like this:
- (void)flipView {
// Setup the view for the back side of the flip
[self performSelector:#selector(performFlip) withObject:nil afterDelay: 0.1];
}
- (void)performFlip {
[UIView transitionWithView: tileToFlip
duration: 0.5
options: UIViewAnimationOptionTransitionFlipFromLeft
animations:^{
// My flip specific code
}
completion:^(BOOL finished) {
}
];
}
In a nutshell, I'm setting everything up in the flipView method, returning control to iOS so it has time to do it's rendering, then kicking off the flipTile selector after a tenth of a second to do the actual animation.
Good luck!
- (void)perform
{
UIViewController *src = (UIViewController *) self.sourceViewController;
UIViewController *dst = (UIViewController *) self.destinationViewController;
[UIView beginAnimations:#"LeftFlip" context:nil];
[UIView setAnimationDuration:0.8];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:src.view.superview cache:YES];
[UIView commitAnimations];
[src presentViewController:dst animated:NO completion:nil];
}

Resources