Since iOS 8, UITextFields in a form behave very strangely. If I click an another text field or press Tab on the keyboard, the entered text animates upwards then reappears quickly. It happens every time after the view did loaded, and every now and then afterwards.
It looks like this:
My code looks like this:
#pragma mark - <UITextFieldDelegate>
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
if (textField == self.passwordTextField) {
[self loginButtonClicked:nil];
} else if (textField == self.emailTextField) {
[self.passwordTextField becomeFirstResponder];
}
return YES;
}
EDIT:
It looks like this issue is caused by my keyboard listeners:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
- (void)keyboardWillHide:(NSNotification *)sender
{
self.loginBoxBottomLayoutConstraint.constant = 0;
[self.view layoutIfNeeded];
}
- (void)keyboardWillShow:(NSNotification *)sender
{
CGRect frame = [sender.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect newFrame = [self.view convertRect:frame fromView:[[UIApplication sharedApplication] delegate].window];
self.loginBoxBottomLayoutConstraint.constant = CGRectGetHeight(newFrame);
[self.view layoutIfNeeded];
}
The problem seems to be that you are executing the piece of code in
-(void)keyboardWillShow:(NSNotification *)sender
even if the keyboard is already active, which leads to some distortion.
A small work around would be to check if the keyboard is already active before adjusting the frames, as below
bool isKeyboardActive = false;
-(void)keyboardWillHide:(NSNotification *)sender
{
self.boxBottomConstraint.constant = 0;
[self.view layoutIfNeeded];
isKeyboardActive = false;
}
-(void)keyboardWillShow:(NSNotification *)sender
{
if (!isKeyboardActive) {
CGRect frame = [sender.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect newFrame = [self.view convertRect:frame fromView:[[UIApplication sharedApplication] delegate].window];
self.boxBottomConstraint.constant = CGRectGetHeight(newFrame);
[self.view layoutIfNeeded];
isKeyboardActive = true;
}
}
Try this
- (void)textFieldDidEndEditing:(UITextField *)textField
{
[textField layoutIfNeeded];
}
Which I guess should resolve your issue. Got some similar post at UITextField: When beginning input, textfield bounces up, and then bounces down
IOS8 Text in TextField Bounces on Focus
Let me know if still we have issue
Try wrapping your code in this
[UIView performWithoutAnimation:^{
// Changes we don't want animated here
}];
Related
I have a UITextView (purpose : comment) pinned at the bottom of my screen, when the user wants to add a comment, the keyboard appears and I have the comment view shift upwards along with the comment. I also have a cancel button to hide the keyboard, but the keyboard isn't hidden
//Set up NSNotification for Keyboard
-(void) viewWillAppear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillToggle:)
name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillToggle:)
name:UIKeyboardWillHideNotification object:nil];
}
//Code to shift comment view up with keyboard
- (void) keyboardWillToggle:(NSNotification *)aNotification
{
CGRect frame = [self.navigationController.toolbar frame];
CGRect keyboard = [[aNotification.userInfo valueForKey:#"UIKeyboardFrameEndUserInfoKey"] CGRectValue];
frame.origin.y = keyboard.origin.y - frame.size.height;
[UIView animateWithDuration:[[aNotification.userInfo valueForKey:#"UIKeyboardAnimationDurationUserInfoKey"] floatValue] animations:^
{
[self.navigationController.toolbar setFrame:frame];
}];
}
//Hide keyboard
-(void)cancelComment:(UIBarButtonItem*)sender{
NSLog(#"cancelComment called");
[self.view endEditing:YES];
}
I feel like this should work? "cancelComment called" is being logged to the console but the keyboard isn't hidden
SOLUTION:
You have forgotten to put:
[yourtextfield resignfirstresponder];
in your cancelComment function.
you can try
-(void)cancelComment:(UIBarButtonItem*)sender{
NSLog(#"cancelComment called”);
[self.navigationController.view endEditing:YES];
}
I think you textView not in self.view and in the self.navigationController.view
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[yourtextfieldname resignfirstresponder];
}
Hope this will you!
i am working on a login screen which contain a scroll view and on the scrollview there are two text fields with a login button.
scrollview used to adjust for the iphone 5 screen size. and i am using a "tab gesture" so the if any user is entering text in text field and want to hide keyboard then can click on anywhere on the screen to hide key board. function used for the tab gesture is
- (void)viewDidLoad {
NSLog(#"login view");
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTapGestureCaptured:)];
[self.scrollView addGestureRecognizer:singleTap]; }
- (void)singleTapGestureCaptured:(UITapGestureRecognizer *)gesture
{
[self.view endEditing:YES]; }
My problem is that when a user is entering text in the textfields using keyboard then in the middle of entering text keyboard detects the tab gesture and hides the keyboard in the middle.
what i did to solve the issue:-
1.) i changed the [self.view addGestureRecognizer:singleTap];
2.) i placed a view on the top of the screen with dimention (0,0,360,400) and apply the gesture to this view so that click on this view will hide keyboard but still when user types keyboard hide by calling gesture method
3.) i also used a button on the scrollview of half of screen size so taht user can click anywhere to hide the keybaord butsill while typing even then keyboard hides y calling the ibaction method of button palced
Remove Tapgesture And try this code , it will be helpful.
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self.view endEditing:YES];
}
Use This to hide the keyboard and show the keyboard:-
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
if (textField == username)
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardDidShowNotification object:nil];
}
if (textField == password)
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardDidShowNotification object:nil];
}
return YES;
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
if (textField == username)
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardDidHideNotification object:nil];
}
if (textField == password)
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardDidShowNotification object:nil];
}
return YES;
}
- (void)keyboardWillShow:(NSNotification *)notification
{
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
float newVerticalPosition = -keyboardSize.height + 100;
[self moveFrameToVerticalPosition:newVerticalPosition forDuration:0.3f];
}
- (void)keyboardWillHide:(NSNotification *)notification
{
CGFloat kNavBarHeight = self.navigationController.navigationBar.frame.size.height;
[self moveFrameToVerticalPosition:kNavBarHeight forDuration:0.3f];
}
- (void)moveFrameToVerticalPosition:(float)position forDuration:(float)duration
{
CGRect frame = self.view.frame;
frame.origin.y = position;
[UIView animateWithDuration:duration animations:^{
self.view.frame = frame;
}];
}
I found the best solution for it. First you integrate the pod 'TPKeyboardAvoiding', '~>1.2.3' and just add the TPKeyboardAvoidingScrollView Class. It will handle all.don't have to write extra code.
try like this,
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[textField1 resignFirstResponder];
[textField2 resignFirstResponder];
}
hope this will help :)
I have the following view hierarchy. View->container->2 UITextfields and 1 button in containerView. The container is in the center of the screen. What I want to do is to move the container up when keyboard appears and UITextfield is behind the keyboard and move back to center when keyboard disappear. Here is the screenshot for the same.
What constraints do I need to change or do I need to add constraints in code ?
Get the frame of the container while keyboard show and update the new frame size. 'setTranslatesAutoresizingMaskIntoConstraints' is the right solution while updating frame of a view.It worked for me
#implementation ViewController
{
CGRect defaultFrame;
}
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
#pragma mark Notifications
- (void)keyboardWillShow:(NSNotification *)notification {
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
defaultFrame = self.ContentView.frame;
[self.ContentView setTranslatesAutoresizingMaskIntoConstraints:YES];
[self.ContentView layoutIfNeeded];
CGRect contentInsets = CGRectMake(defaultFrame.origin.x, (keyboardSize.height), defaultFrame.size.width, defaultFrame.size.height);
[UIView animateWithDuration:0.5f
animations:^{
self.ContentView.frame = contentInsets;
}
completion:^(BOOL finished){
}
];
self.ContentView.frame = contentInsets;
}
- (void)keyboardWillHide:(NSNotification *)notification {
[self.ContentView setTranslatesAutoresizingMaskIntoConstraints:NO];
[UIView animateWithDuration:0.5f
animations:^{
self.ContentView.frame = defaultFrame;
}
completion:^(BOOL finished){
}
];
}
As I understand the question, you are trying to shift the entire view when the UITextField becomes the first responder (i.e. adds the keyboard to the view)? If that is the case, I would add code in the UITextField delegate method:
#define VIEW_TAG 12345
#define kKeyboardOffsetY 80.0f
- (void)textFieldDidBeginEditing:(UITextField *)textField {
// get a reference to the view you want to move when editing begins
// which can be done by setting the tag of the container view to VIEW_TAG
UIView *containerView = (UIView *)[self.view viewWithTag:VIEW_TAG];
[UIView animateWithDuration:0.3 animations:^{
containerView.frame = CGRectMake(0.0f, -kKeyboardOffsetY, containerView.frame.size.width, containerView.frame.size.height);
}];
}
- (void)textFieldDidEndEditing:(UITextField *)textField {
UIView *containerView = (UIView *)[self.view viewWithTag:VIEW_TAG];
[UIView animateWithDuration:0.3 animations:^{
containerView.frame = CGRectMake(0.0f, self.view.frame.origin.y, containerView.frame.size.width, containerView.frame.size.height);
}];
}
add UITextFieldDelegate in .h file
and try the following code it will surely help you
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
if (textField == username)
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardDidShowNotification object:nil];
}
if (textField == password)
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardDidShowNotification object:nil];
}
return YES;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
if (textField == username)
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardDidHideNotification object:nil];
}
if (textField == password)
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardDidShowNotification object:nil];
}
return YES;
}
- (void)keyboardWillShow:(NSNotification *)notification
{
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
float newVerticalPosition = -keyboardSize.height + 100;
[self moveFrameToVerticalPosition:newVerticalPosition forDuration:0.3f];
}
- (void)keyboardWillHide:(NSNotification *)notification
{
CGFloat kNavBarHeight = self.navigationController.navigationBar.frame.size.height;
[self moveFrameToVerticalPosition:kNavBarHeight forDuration:0.3f];
}
- (void)moveFrameToVerticalPosition:(float)position forDuration:(float)duration
{
CGRect frame = self.view.frame;
frame.origin.y = position;
[UIView animateWithDuration:duration animations:^{
self.view.frame = frame;
}];
}
Take IBOutlet of your bottom constraint or top constraint of container view by ctrl+drag from respactive constraint.
If bottom constraint then increase the constant of constraint equal to keyboard height when keyboard appears and decrease same when keyboard disappear.
If using top constraint then decrease the constant equal to keyboard height when keyboard appears and increase same when keyboard disappear.
for example,
topConstraint.constant = topConstraint.constant + keyboardHeight;
Update :
According to your constraint you should take outlet of vertically center or center x and you should do something like,
self.verticallyCenter.constant = self.horizontalyCenter.constant - 100 //here 100 is keyboardheight for example and do it in viewdidload
By this your container view will goes up to 100 pixels.
when resign keyboard you can add 100 to it's constant to get initial position back.
Hope this will help :)
Seems like you have given correct constraints all you need to do now is to make a outlet of centre y constraint and change it's constant on keyboard show/hide events, Which you can grab with keyboardDidShow/keyboardWillShow and keyboardDidHide/keyboardWillHide notifications. that said you can also add cool animation effects for these changes. Try out let me know if you need example.
Edit:
add your viewcontroller as observer for two Notifications:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardDidHide:)
name:UIKeyboardDidHideNotification
object:nil];
Now suppose name of your constraint is "constraintForTopSpace",then add two methods for the notifications:
- (void)keyboardWasShown:(NSNotification *)notification {
// Get the size of the keyboard.
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
//Given size may not account for screen rotation
int height = MIN(keyboardSize.height,keyboardSize.width);
// Here you can set your constraint's constant to lift your container up.
[UIView animateWithDuration:0.5 animations:^{
[constraintForTopSpace setConstant:constraintForTopSpace.constant - height];
[self.view layoutIfNeeded];
}];
}
- (void)keyboardDidHide:(NSNotification *)notification {
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
int height = MIN(keyboardSize.height,keyboardSize.width);
// Here you can set your constraint's constant to move your container down.
[UIView animateWithDuration:0.5 animations:^{
[constraintForTopSpace setConstant:constraintForTopSpace.constant + height];
[self.view layoutIfNeeded];
}];
}
And you can also use UIKeyboardWillShowNotification/UIKeyboardWillHideNotification notification they will be triggered before the keyboard appears on screen, Its up to your requirements.
Here adding animation will give smooth look and feel. ;)
The modal dialog gets moved up when they keyboard appears and moves down when the keyboard disappears.
All is fine till I rotate the iPad. In any other orientation except the standard it doesn't work. When the iPad is turned around the modal dialog moves down when the keyboard appears instead of up and up when the keyboard disappears instead of down.
This is the code I am using to position the modal dialog when keyboard appears/disappears.
- (void)textFieldDidBeginEditing:(UITextField *)textField {
self.view.superview.frame = CGRectMake(self.view.superview.frame.origin.x, 140, self.view.superview.frame.size.width, self.view.superview.frame.size.height);
}
}];
}
-(void)textFieldDidEndEditing:(UITextField *)textField {
[UIView animateWithDuration:0.4 animations:^ {
self.view.superview.frame = CGRectMake(self.view.superview.frame.origin.x, 212, self.view.superview.frame.size.width, self.view.superview.frame.size.height);
}
}];
}
Instead of setting the frame, use CGAffineTransformTranslate, for example like so:
- (void)textFieldDidBeginEditing:(UITextField *)textField {
self.view.superview.transform = CGAffineTransformTranslate(self.view.superview.transform,0,72);
}
}];
}
-(void)textFieldDidEndEditing:(UITextField *)textField {
[UIView animateWithDuration:0.4 animations:^ {
self.view.superview.transform = CGAffineTransformTranslate(self.view.superview.transform,0,-72);
}
}];
}
You should try using Keyboard Notifications:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWasShown:) name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillBeDismissed:) name:UIKeyboardWillHideNotification object:nil];
and then in the selectors adjust the frame. Not in textFieldDidBeginEditing/textFieldDidEndEditing.
- (void)keyboardWasShown:(NSNotification *) notification {
NSDictionary *info = [notification userInfo];
NSValue *aValue = [info objectForKey:UIKeyboardFrameEndUserInfoKey];
CGSize keyboardSize = [aValue CGRectValue].size;
keyboardHeight = MIN(keyboardSize.height, keyboardSize.width);
// set new frame based on keyboard size
- (void)keyboardWillBeDismissed: (NSNotification *) notification{
[UIView animateWithDuration:0.4 animations:^{
// original frame
}];
}
I have a mainview with all of my textfields and buttons. For my textfields i am using the inputView to display UIPickerViews instead of the keyboards. I am wondering how I can main the view move up when a textfield is selected that way the picker and the pickers toolbar does not cover up the textfield, because i have some textfields at the bottom that get covered by it. I have tried using the following code from a tutorial with a table view, but it does not work for me. It builds without error, but it does not work right. The view just disappears and then it only comes back down half way when the pickerView is dismissed.
- (void)viewDidLoad {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(pickerShown:) name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(pickerHidden:) name:UIKeyboardWillHideNotification object:nil];
}
-(void)pickerShown:(NSNotification *)note {
CGRect pickerFrame;
[[[note userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&pickerFrame];
CGRect scrollViewFrame = mainView.frame;
scrollViewFrame.size.height -= pickerFrame.size.height;
[mainView setFrame:pickerFrame];
}
-(void)pickerHidden:(NSNotification*)note{
[mainView setFrame:self.view.bounds];
}
Is this close to what i need to be doing?
May I suggest having a look at this tutorial "Sliding UITextFields around to avoid the keyboard".
In your case, you need to put the code they have in textFieldDidBeginEditing in your pickerShown method, and change the constants that they have for keyboard heights for the picker heights instead.
Hope this helps :)
For those looking for alternative solution, here's one. I made it into a library for repeated use in complex project.
/* In Keyboard.m */
static NSUInteger verticalOffset = 0;
+ (void)moveViewForKeyboard:(UITextField *)theTextField inView:(UIView *)view
{
/* Move 200 for keyboard, change the number for other types */
[self moveViewUp:view withOffset:theTextField.frame.origin.y - 200];
}
+ (void)moveViewUp:(UIView *)view withOffset:(int)offset
{
if(offset < 0)
offset = 0;
if(offset != verticalOffset)
{
[self moveView:view withOffset:offset - verticalOffset];
verticalOffset = offset;
}
}
+ (void)moveViewOnEndEditing:(UIView *)view
{
if(verticalOffset != 0)
{
[self moveView:view withOffset:-verticalOffset];
verticalOffset = 0;
}
}
+ (void)moveView:(UIView *)view withOffset:(int)offset
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
CGRect rect = view.frame;
rect.origin.y -= offset;
rect.size.height += offset;
view.frame = rect;
[UIView commitAnimations];
}
And use it this way in the views:
- (void)textFieldDidBeginEditing:(UITextField *)theTextField
{
[Keyboard moveViewForKeyboard:theTextField inView:self.view];
}
- (void)textFieldDidEndEditing:(UITextField *)theTextField
{
[Keyboard moveViewOnEndEditing:self.view];
}