iOS keyboard animation conflict - ios

I am currently writing an iOS app and encountered some animation issue. The following is the test code to show my question. It's just a very simple animation that lets the textField to move up when the keyboard shows and move down when the keyboard hides. Interestingly, if it is an English keyboard, it seems that the UIView animation somehow conflicts with the keyboard animation and no animations are performed, but if I switch to the Chinese keyboard, it works fine. I just want to confirm that whether it is a bug from apple....
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UITextField *textField = [[UITextField alloc] init];
self.textField = textField;
textField.placeholder = #"Click me!!";
textField.frame = CGRectMake(100, 350, 150, 40);
[self.view addSubview:self.textField];
self.textField.delegate = self;
}
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
[UIView animateWithDuration:0.25 animations:^{
CGRect frame = self.textField.frame;
frame.origin.y -= 100;
self.textField.frame = frame;
}];
return YES;
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[self.textField resignFirstResponder];
[UIView animateWithDuration:0.25 animations:^{
CGRect frame = self.textField.frame;
frame.origin.y += 100;
self.textField.frame = frame;
}];
return YES;
}
UPDATE
It seems that it is a bug from apple... I tried to use iOS 8.3 simulator, and it works super smoothly... In iOS 9.3, if you just try showing and hiding the keyboard, even without moving the textField, the animation will get stuck after several operations...

I'd advise you to move the animation blocks to methods from the notification UIKeyboardWill{Show|Hide}Notification. The delegate methods from your text field are asking about the text field and its behavior – nothing to do with the keyboard itself (and you can even synchronize the duration, curve and delay).
You're returning YES to -textFieldShouldReturn: which is only supposed to check if the text field should process the return key tap.
From my experience with animations, sometimes everything works fine when testing with a real device. I made the suggested changes over here and everything worked fine on an iPhone 5c (iOS 8.1) and iPhone 6s Plus (iOS 10, Beta 1).
Here's a snippet of how it looks like:
- (void)viewDidLoad {
[super viewDidLoad];
[self setupNotifications];
[self initUIElements];
}
- (void)initUIElements {
CGRect frame = CGRectMake(0.f, 20.f, 200.f, 44.f);
self.textField = [[UITextField alloc] initWithFrame:frame];
self.textField.center = CGPointMake(self.view.center.x, 32.f);
self.textField.placeholder = #"Placeholder";
self.textField.delegate = self;
[self.view addSubview:self.textField];
self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 50.f, 50.f)];
self.imageView.center = self.view.center;
self.imageView.backgroundColor = [UIColor magentaColor];
[self.view addSubview:self.imageView];
}
- (void)setupNotifications {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
}
- (void)keyboardWillHide:(id)sender {
[UIView animateWithDuration:1.f animations:^{
self.textField.center = CGPointMake(self.view.center.x, 32.f);
self.imageView.center = self.view.center;
}];
}
- (void)keyboardWillShow:(id)sender {
[UIView animateWithDuration:1.f animations:^{
self.textField.center = CGPointMake(self.view.center.x, 62.f);
self.imageView.center = CGPointMake(self.view.center.x, (self.view.center.y - 50.f));
}];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return YES;
}

#lin fu
.m
- (void)viewDidLoad {
[super viewDidLoad];
UITextField *textField = [[UITextField alloc] init];
textField.placeholder = #"Click me!!";
textField.delegate = self;
textField.frame = CGRectMake(100, 350, 150, 40);
[self.view addSubview:textField];
}
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
[UIView animateWithDuration:0.25 animations:^{
CGRect frame = textField.frame;
frame.origin.y -= 100;
textField.frame = frame;
}];
return YES;
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
[UIView animateWithDuration:0.25 animations:^{
CGRect frame = textField.frame;
frame.origin.y += 100;
textField.frame = frame;
}];
return YES;
}
in .h
Try this out. It works for me.

you have another option you can use the third party library call TPAvoidingKeyBoard it will help you out in there

Related

becomeFirstResponder not show keyboard in ios 11

I tried to show a keyboard on after loading screen like this:
-(void) viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
UITextField *tf = [[UITextField alloc] initWithFrame:CGRectMake(10, 200, 300, 40)];
tf.borderStyle = UITextBorderStyleRoundedRect;
tf.text = #"test";
[self.view addSubview:tf];
if([tf canBecomeFirstResponder]){
[tf becomeFirstResponder]; // surely this line is called
}
}
This code works on ios 8,9,10 but not 11. I'm not sure why the keyboard isn't show automatically on ios 11 while text field is focusing (has cursor).
And in this case, keyboard's notification isn't called:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
- (void) keyboardWillShow:(NSNotification *)note {
NSDictionary *userInfo = [note userInfo];
CGSize kbSize = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
DLog(#"Keyboard Height: %f Width: %f", kbSize.height, kbSize.width);
}
I even try this:
[tf performSelector:#selector(becomeFirstResponder) withObject:nil afterDelay:0];
but still not work.
I have to click on text field to bring up the keyboard.
Is there anything update from Apple which I don't know?
Update: it looks like there is something wrong with my project or all my view controllers because I can't make the keyboard showing on all screens. But when I create new project with above code, it can work well.
Here is one of the problem:
As you can see, I have to click on the textfield to show the keyboard, and from the second time, it can work properly. And this issue only happended on ios 11 (both simulator & device)
Here is the code for search field above:
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 215, 30)];
textField.backgroundColor = [UIColor clearColor];
textField.placeholder = #"Enter text to search";
textField.borderStyle = UITextBorderStyleLine;
textField.layer.masksToBounds=YES;
textField.layer.borderColor=[[UIColor lightGrayColor]CGColor];
textField.layer.borderWidth= 1.0f;
textField.returnKeyType = UIReturnKeySearch;
textField.delegate = self;
textField.clearButtonMode = UITextFieldViewModeAlways;
[UIView transitionWithView:self.navigationController.navigationBar
duration:0.55f
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
self.navigationItem.titleView = textField;
} completion:^(BOOL finished) {
[textField becomeFirstResponder];
}];
I wonder is there anything cause conflict keyboard?
When the TextField is not yet being drawn on the screen, then becomeFirstResponder() will not work. For example when it was hidden and never drawn. Then you need to call becomeFirstResponder() after it has been drawn. Maybe this will help:
DispatchQueue.main.async {
tf.becomeFirstResponder()
}
I have created a new project and tried your code. It works normally on both simulator and device iOS11. Keyboard is showed and notification is called. This is the code i have tried.
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
UITextField* tf = [[UITextField alloc] initWithFrame:CGRectMake(10, 200, 300, 40)];
tf.borderStyle = UITextBorderStyleRoundedRect;
tf.text = #"test";
[self.view addSubview:tf];
if ([tf canBecomeFirstResponder]) {
[tf becomeFirstResponder]; // surely this line is called
}
}
- (void)keyboardWillShow:(NSNotification*)note {
NSDictionary* userInfo = [note userInfo];
CGSize kbSize = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
NSLog(#"Keyboard Height: %f Width: %f", kbSize.height, kbSize.width);
}
#end
You should check DLog method. I think keyboard's notification is called but nothing is logged because of DLog method.
Try this one. I feel textField object is getting null in completion block and your calling becomeFirstResponder on that.
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 215, 30)];
textField.backgroundColor = [UIColor clearColor];
textField.placeholder = #"Enter text to search";
textField.borderStyle = UITextBorderStyleLine;
textField.layer.masksToBounds=YES;
textField.layer.borderColor=[[UIColor lightGrayColor]CGColor];
textField.layer.borderWidth= 1.0f;
textField.returnKeyType = UIReturnKeySearch;
textField.delegate = self;
textField.clearButtonMode = UITextFieldViewModeAlways;
[UIView transitionWithView:self.navigationController.navigationBar
duration:0.55f
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
self.navigationItem.titleView = textField;
} completion:^(BOOL finished) {
[((UITextField *)self.navigationItem.titleView) becomeFirstResponder];
}];
try this;
- (BOOL)textFieldShouldReturn:(UITextField *)theTextField {
[theTextField resignFirstResponder];
return NO;
}
- (void)viewWillAppear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)keyboardWillShow:(NSNotification *)notification {
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
}
- (void)keyboardWillHide:(NSNotification *)notification {
}
In my case the problem was, that I had 2 UIWindow objects and the one I used to add UI elements was not set as key window, and keyboard window had lower level, so keyboard was covered by my other window. I just had to call makeKeyAndVisible() on the second window. john07's comment helped me figure this out. For further reference check: https://developer.apple.com/library/archive/qa/qa1813/_index.html
It's really weird, because this issue can be fixed after showing a UIAlertView
So when I try to add a UIAlertView with loading indicator (and auto dimiss after few seconds) like this before showing keyboard with above code, it can work well.
Don't know the root cause of my project, but it works.
And it only happens on ios 11.

Send button is not working when keyboard opened in iOS

I am stuck in very simple functionality in iOS.
I am trying to send the data from a textField which is inside the subview of a scroll view. Button is firing the action when I hit the button, when keyboard is closed as soon as I try to write something and keyboard opened button stop responding.
VideoViewController:
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
controller.videoID = videoID;
controller.channelID = channelID;
controller.view.frame = self.commentView.bounds;
[self.commentView addSubview:controller.view];
// [self.scrollView addSubview:controller.sendBtn];
[self addChildViewController:controller];
[controller didMoveToParentViewController:self];
}
CommentViewController:
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
controller.videoID = videoID;
controller.channelID = channelID;
controller.view.frame = self.commentView.bounds;
[self.commentView addSubview:controller.view];
// [self.scrollView addSubview:controller.sendBtn];
[self addChildViewController:controller];
[controller didMoveToParentViewController:self];
}
-(void)keyboardWillShow:(NSNotification *)notification
{
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
[UIView animateWithDuration:0.3 animations:^{
CGRect f = self.view.frame;
f.origin.y = -keyboardSize.height+100;
self.sendView.frame = f;
}];
_sendBtn.userInteractionEnabled = YES;
}
-(void)keyboardWillHide:(NSNotification *)notification
{
[UIView animateWithDuration:0.3 animations:^{
CGRect f = self.view.frame;
f.origin.y = 0.0f;
self.sendView.frame = f;
}];
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[commentTextField resignFirstResponder];
return YES;
}
- (BOOL)touchesShouldCancelInContentView:(UIView *)view
{
return ![view isKindOfClass:[UIButton class]];
}
Please suggest something on this.
Thank you.
I faced this problem, too
It took me 2 days to find the solution. You need to set the cancel touches flag to false for ScrollVIew/View.
Actually, scrollview touch is enable and it is not allowing the button to interact.
This is the only reason send button is not working.

How to move View up when Keyboard appeared in small screen like 4s , 5 and 5s but view should not move up when its enter inside iphone 6

How to move View up when Keyboard appeared in small screen like 4s, 5 and 5s but view should not move up when its enter inside iphone 6 and 6S.
I am sharing my code which is i have done in my app for all screen but in my condition view should not move up when its enter in 6 or 6s.
-(void)textFieldDidBeginEditing:(UITextField *)textField
{
[self animateTextField:textField up:YES];
}
-(void)textFieldDidEndEditing:(UITextField *)textField
{
[self animateTextField:textField up:NO];
}
-(void)animateTextField:(UITextField*)textField up:(BOOL)up
{
const int movementDistance = -60; // tweak as needed
const float movementDuration = 0.3f; // tweak as needed
int movement = (up ? movementDistance : -movementDistance);
[UIView beginAnimations: #"animateTextField" context: nil];
[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration: movementDuration];
self.view.frame = CGRectOffset(self.view.frame, 0, movement);
[UIView commitAnimations];
}
I suggest you use IQKeyboardManager It will manage everything for you with less efforts
// Add a scrollview on main view and add UITextField on that scrollview
-(void) viewDidLoad
{
UIScrollView *myScrollView = [ [UIScrollView alloc] initWithFrame:[UIScreen mainScreen ].bounds];
[myScrollView .contentSize =CGSizeMake(320, 500);
[myScrollView .contentInset = UIEdgeInsetsMake(0, 0, 60, 0);
[self.view addSubView:myScrollView ];
UITextField *myTextField = [ [UITextField alloc] initWithFrame:CGRectMake(20,30,100,33)];
[myScrollView addSubView:myTextField ];
myTextField.delegate = self;
}
// Set the scrollview content offset to make the myTextField move up
- (void) textFieldDidBeginEditing:(UITextField *)textField
{
[myScrollView setContentOffset:CGPointMake(0,textField.center.y-80) animated:YES];
// here '80' can be any number which decide the height that textfiled should move
}
//To move the textfield to its original position
- (BOOL) textFieldShouldReturn:(UITextField *)textField
{
[[myScrollView setContentOffset:CGPointMake(0,0) animated:YES];
[textField resignFirstResponder];
return YES;
}

iOS 8 CGAffineTransformConcat with Scale and Translate cause a position jump

I am having an issue with CGAffineTransformConcat that is present in iOS 8, but not iOS 7. When animating a UIView using a concatenation with a scale and translate causes the position to jump. Running the same code in iOS 7, achieves the desired results. Is there something that has changed that causes this issue?
Here is my example code...
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//add a view
self.lilView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
self.lilView.backgroundColor = [UIColor greenColor];
[self.view addSubview:self.lilView];
//add a tap gesture
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(poop:)];
[self.view addGestureRecognizer:tap];
}
-(void) poop:(UITapGestureRecognizer*) gesture {
if (!self.pooped) {
[UIView animateWithDuration:1 delay:0 options:0 animations:^{
self.lilView.transform = CGAffineTransformConcat(CGAffineTransformMakeScale(2.0, 2.0), CGAffineTransformMakeTranslation(200, 300));
self.pooped = YES;
} completion:nil];
} else {
[UIView animateWithDuration:1 delay:0 options:0 animations:^{
self.lilView.transform = CGAffineTransformConcat(CGAffineTransformMakeScale(1.5, 1.5), CGAffineTransformMakeTranslation(100, 200));
self.pooped = NO;
} completion:nil];
}
}
Thank you for your help!

View is not set back to original position

In my xib i have set one text box ...when user edit in it i am moving that view little up...but when i return back it to its original postion it not come to its original postion it remain little up then original postion.
Here is viewDidLoad
- (void)viewDidLoad
{
[super viewDidLoad];
if ([self respondsToSelector:#selector(edgesForExtendedLayout)])self.edgesForExtendedLayout = UIRectEdgeNone;
search=FALSE;
UIButton *btnOther = [UIButton buttonWithType:UIButtonTypeSystem]; //UIButtonTypeCustom for image button
[btnOther setTitle:#"Save" forState:UIControlStateNormal];
btnOther.titleLabel.font = [UIFont fontWithName:GZFont size:12.0f];
// [btnSave setImage:[UIImage imageNamed:#"save.png"] forState:UIControlStateNormal];
[btnOther addTarget:self action:#selector(btnSaveAction:) forControlEvents:UIControlEventTouchUpInside];
[btnOther setFrame:CGRectMake(0, 0, 55, 29)];
dataArray=[[NSMutableArray alloc]init];
nameSearchArray=[[NSMutableArray alloc]init];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:btnOther];
txtCharityName.hidden=YES;
txtCharityMail.hidden=YES;
originalCenter=self.view.center;
}
here is textfield delegate methods.:
- (void)textFieldDidBeginEditing:(UITextField *)textField {
if(textField==txtGratuity){
self.view.center=CGPointMake(originalCenter.x, originalCenter.y-30);
}
}
- (void)textFieldDidEndEditing:(UITextField *)textField {
self.view.center=CGPointMake(originalCenter.x, originalCenter.y);
charityId=#"";
NSLog(#"charityID%#",charityId);
}
and here is screenshot.:
as per this equation
frame.origin = center - (bounds.size / 2.0)
center = frame.origin + (bounds.size / 2.0)
you should add 30 points for textfield to get to correct position.
- (void)textFieldDidEndEditing:(UITextField *)textField {
self.view.center=CGPointMake(originalCenter.x, originalCenter.y+30);
charityId=#"";
NSLog(#"charityID%#",charityId);
}
Edit:
try this in your
- (void)textFieldDidBeginEditing:(UITextField *)textField {
[UIView animateWithDuration:0.25
delay:0.0
options: UIViewAnimationOptionCurveEaseInOut
animations:^{
CGRect frame;
// let's move our textField
frame = textField.frame;
frame.origin.y = frame.origin.y-30;
textField.frame=frame;
}
completion:^(BOOL finished){
if(finished) NSLog(#"Finished !!!!!);
}];
}
and move textfield down after edit
- (void)textFieldDidEndEditing:(UITextField *)textField {
[UIView animateWithDuration:0.25
delay:0.0
options: UIViewAnimationOptionCurveEaseInOut
animations:^{
CGRect frame;
// let's move our textField
frame = textField.frame;
frame.origin.y = frame.origin.y+30;
textField.frame=frame;
}
completion:^(BOOL finished){
if(finished) NSLog(#"Finished !!!!!);
}];
}
Set the textfield frames in viewWillAppear instead of viewDidLoad method.

Resources