I'm coding a login view, when the keyboard show, background will move the same distance with an animation, but I find a question that I can't understand, when the animation begin, at the top of the background will display a white area, the white are is just the area that will disappear when the animation finished.
Here is my code
- (void)keyboardWillShow:(NSNotification *)notification{
CGRect keyboardBounds;
[[notification.userInfo valueForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardBounds];
NSNumber * duration = [notification.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey];
NSNumber * curve = [notification.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey];
keyboardBounds = [self.view convertRect:keyboardBounds toView:nil];
CGRect viewFrame = self.view.frame;
viewFrame.origin.y = 0 - keyboardBounds.size.height;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:[duration doubleValue]];
[UIView setAnimationCurve:[curve intValue]];
[UIView setAnimationDelegate:self];
self.bgView.frame = viewFrame;
[UIView commitAnimations];
}
Thanks in advance!
Related
I know that this question is asked many times, but I can not figure out where am I making mistake. In simple words I can not implement it properly.
I have App which has to work on iPhone and iPad (in portrait orientation only). I have a subclassed UITextField. I need to move it up when it is hidden by keyboard during the edit.
I can not set it properly, because the calculation of the size of the keyboard is done after it enters in the edit mode.
I know that I need following steps:
Register observer
Have routine that calculates Keyboard rectangle from which I can take height
Have 2 events on show and hide of the keyboard to make offset of my custom text field.
Please tell me where I am wrong.
My code is:
Register observer:
- (id)initWithCoder:(NSCoder *)aDecoder{
if (self = [super initWithCoder:aDecoder]) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillChange:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillChange:) name:UIKeyboardDidShowNotification object:nil];
_leftInlineImage = NO;
}
return self;
}
Calculating keyboard height:
- (void)keyboardWillChange:(NSNotification *)notification {
NSDictionary* d = [notification userInfo];
CGRect r = [d[UIKeyboardFrameEndUserInfoKey] CGRectValue];
r = [self.superview convertRect:r fromView:nil];
_keyboardHeight = r.size.height;
}
Show/hide keyboard:
/* Move keyboard */
-(void)showKeyboardWithMove {
CGRect screenRect = [[UIScreen mainScreen] bounds];
////CGFloat screenWidth = screenRect.size.width;
CGFloat screenHeight = screenRect.size.height;
//_keyboardHeight = KEYBOARD_HEIGHT;
if (self.frame.origin.y + self.frame.size.height > screenHeight - _keyboardHeight) {
double offset = screenHeight - _keyboardHeight - self.frame.origin.y - self.frame.size.height;
CGRect rect = CGRectMake(0, offset, self.superview.frame.size.width, self.superview.frame.size.height);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
self.superview.frame = rect;
[UIView commitAnimations];
}
}
-(void)hideKeyboardWithMove {
CGRect rect = CGRectMake(0, 0, self.superview.frame.size.width, self.superview.frame.size.height);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
self.superview.frame = rect;
[UIView commitAnimations];
}
The calculation is made before and my height is 0. All this is done in the subclass of the UITextField.
Add an observer of UIKeyboardWillChangeFrameNotification to the viewDidLoad;
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardFrameDidChange:) name:UIKeyboardWillChangeFrameNotification object:nil];
This method will help you :
- (void)keyboardFrameDidChange:(NSNotification *)notification
{
CGRect keyboardEndFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect keyboardBeginFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
UIViewAnimationCurve animationCurve = [[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] integerValue];
NSTimeInterval animationDuration = [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] integerValue];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];
CGRect newFrame = self.view.frame;
CGRect keyboardFrameEnd = [self.view convertRect:keyboardEndFrame toView:nil];
CGRect keyboardFrameBegin = [self.view convertRect:keyboardBeginFrame toView:nil];
newFrame.origin.y -= (keyboardFrameBegin.origin.y - keyboardFrameEnd.origin.y);
self.view.frame = newFrame;
[UIView commitAnimations];
}
that gives you back the height of the keyboard.
NSNotification * note = // ... the notification you receive via UIKeyboardWillShowNotification
id _obj = [note.userInfo valueForKey:#"UIKeyboardBoundsUserInfoKey"];
CGRect _keyboardBound = CGRectNull;
if ([_obj respondsToSelector:#selector(getValue:)]) [_obj getValue:&_keyboardBound];
the _keyboardBound will have the correct size.
NOTE: that is not a full implementation to handle the keyboard's appearance, if you need the complex idea, please check my complete and accepted answer here (stackoverflow.com internal link).
I am trying to make an image start at coordinates x=80 and y=249 which would move to x=284 and y=99. Then from there it would go to x=488 and y=249.
This is what i got, but for some reason the image starts at x=284 and y=99 and moves to x=488 and y=249.
I need help to fix this issue.
-(void)BallArchR{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration: 1.5];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
CGPoint center = [Ball center];
center.x = 284;
center.y = 99;
[Ball setCenter:center];
[UIView commitAnimations];
[self BallArchR2];
}
-(void)BallArchR2{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration: 1.5];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
CGPoint center = [Ball center];
center.x = 488;
center.y = 249;
[Ball setCenter:center];
[UIView commitAnimations];
}
because of you call BallArchR2 method from BallArchR method directly. But in actual, the animation of BallArchR method is not complete and before that BallArchR2 method is called. So, call BallArchR2 method after the completion of first BallArchR method animation. So you can Try this hope it helps you:
-(void)BallArchR{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration: 1.5];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
CGPoint center = [Ball center];
center.x = 284;
center.y = 99;
[Ball setCenter:center];
[UIView commitAnimations];
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 1.55 * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[self BallArchR2];
});
}
-(void)BallArchR2{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration: 1.5];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
CGPoint center = [Ball center];
center.x = 488;
center.y = 249;
[Ball setCenter:center];
[UIView commitAnimations];
}
I'm trying to resize an image (tiny and return to original size). This code is working for resize the image but never go back to the original size. I thin I miss something in the endItem1Animation code. Any suggestions? Thanks
if (CGRectIntersectsRect(image.frame, item1.frame)) {
item1.hidden = YES;
// Item 1 Animation (Go Tiny)
[UIView beginAnimations:NULL context:NULL];
[UIView setAnimationsEnabled:YES];
[UIView setAnimationDelay:0];
[UIView setAnimationDuration:0];
[UIView setAnimationRepeatCount:0];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationRepeatAutoreverses:NO];
CGRect newRect = image.frame;
newRect.size = CGSizeMake(25,25);
image.frame = newRect;
[UIView commitAnimations];
[self endItem1Animation];
This is the endItem1Animation code:
// Item 1 End Animation (Return to Original Size)
[UIView beginAnimations:NULL context:NULL];
[UIView setAnimationsEnabled:YES];
[UIView setAnimationDelay:0];
[UIView setAnimationDuration:5.0];
[UIView setAnimationRepeatCount:0];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationRepeatAutoreverses:NO];
CGRect newRect = image.frame;
newRect.size = CGSizeMake(50,50);
image.frame = newRect;
[UIView commitAnimations];
The problem is that when you call beginAnimations / endAnimation, this does not block the main thread from running, so calling [self endItem1Animation] sets the second animation which will prevent the first animation from running.
You'll want to use the UIView animation block method instead, which lets you supply a completion handler when the animation completes.
[UIView animateWithDuration:0.5 animations:^{
CGRect newRect = image.frame;
newRect.size = CGSizeMake(25,25);
image.frame = newRect;
} completion:^(BOOL finished) {
[self endItem1Animation];
}];
Another, more straightforward issue, is that the duration for the first animation is zero.
I fix this issue running a selector at the end of the code. Now my code is working. Here is my final code, I Hope to help someone. Thank you for your suggestions.
if (CGRectIntersectsRect(image.frame, item1.frame)) {
item1.hidden = YES;
// Item 1 Animation (Go Tiny)
[UIView beginAnimations:NULL context:NULL];
[UIView setAnimationsEnabled:YES];
[UIView setAnimationDelay:0];
[UIView setAnimationDuration:0];
[UIView setAnimationRepeatCount:0];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationRepeatAutoreverses:NO];
CGRect newRect = image.frame;
newRect.size = CGSizeMake(25,25);
image.frame = newRect;
[UIView commitAnimations];
[self performSelector:#selector(endItem1Animation) withObject:nil afterDelay:8.0];
I am doing an animation to show the text view on top keyboard when UIKeyboardWillShowNotification is being broadcasted like following
-(void) keyboardWillShow:(NSNotification *)notification{
// get keyboard size and loctaion
NSDictionary *info = [notification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
NSNumber *duration = [notification.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey];
__block CGRect containerFrame = containerView.frame;
containerFrame.origin.y = self.view.bounds.size.height - (kbSize.height + containerFrame.size.height);
[UIView animateWithDuration:[duration doubleValue]
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
containerView.frame = containerFrame;
} completion:^(BOOL finished) {
nil;
}
];
}
An animation is not good enough.If you can give it a try and will see small issue at the end of animation.
I googled and found out that there is another way to do an animation and it works perfectly :
-(void) keyboardWillShow:(NSNotification *)note{
// get keyboard size and loctaion
CGRect keyboardBounds;
[[note.userInfo valueForKey:UIKeyboardFrameEndUserInfoKey] getValue: &keyboardBounds];
NSNumber *duration = [note.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey];
NSNumber *curve = [note.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey];
// Need to translate the bounds to account for rotation.
keyboardBounds = [self.view convertRect:keyboardBounds toView:nil];
// get a rect for the textView frame
CGRect containerFrame = containerView.frame;
containerFrame.origin.y = self.view.bounds.size.height - (keyboardBounds.size.height + containerFrame.size.height);
// animations settings
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:[duration doubleValue]];
[UIView setAnimationCurve:[curve intValue]];
// set views with new info
containerView.frame = containerFrame;
// commit animations
[UIView commitAnimations];
}
However, according to the documentation, we are not recommended to use this animation in Ios 4 and later on...
I can not tell any differences between my codes compared to the latter one. Why my codes can not do perfect animation. Please help if you have any ideas.
It's the animation curve. The example you cite is matching its animation curve as well its duration to those of the keyboard. Your code doesn't. Your structure should look more like this:
NSNumber* curve = info[UIKeyboardAnimationCurveUserInfoKey]; // *
NSNumber* duration = info[UIKeyboardAnimationDurationUserInfoKey];
[UIView animateWithDuration:duration.floatValue delay:0
options:curve.integerValue << 16 // *
animations: ^{ // ...
So I have an App of which I animate some UI Elements as soon as the app opens. These animations are done using simple UIView Animations. Below is a sample of the viewDidLoad portion
//animate settings in the frame
CGRect settingsFrame = settingsView.frame;
settingsFrame.origin.x = -104;
settingsFrame.origin.y = 457;
settingsView.frame = settingsFrame;
//animate about in the frame
CGRect aboutFrame = aboutView.frame;
aboutFrame.origin.x = -104;
aboutFrame.origin.y = 457;
aboutView.frame = aboutFrame;
And here is a the corresponding method portion that is called.
CGRect settingsFrame = settingsView.frame;
settingsFrame.origin.x = 0; // new x coordinate
settingsFrame.origin.y = 457; // new y coordinate
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration: 1];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
settingsView.frame = settingsFrame;
CGRect aboutFrame = aboutView.frame;
aboutFrame.origin.x = 104; // new x coordinate
aboutFrame.origin.y = 457; // new y coordinate
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration: 1];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
aboutView.frame = aboutFrame;
There are 4 more matching sets of code to finish out the animation. My problem is, whenever the viewDidLoad portion is enabled (not commented out) it slows down the other transitions to xib's in my App. Do you guys have any idea how I can keep these animations but not have the slow transitions?
In addition to that, I should say this is being developed on iOS 7 and Xcode 5 Developer Preview, so I'm not ruling out a bug...
You forgot to add commitAnimations at the end of the animation block...
Do below, you problem will be fixed.
CGRect settingsFrame = settingsView.frame;
settingsFrame.origin.x = 0; // new x coordinate
settingsFrame.origin.y = 457; // new y coordinate
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration: 1];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
settingsView.frame = settingsFrame;
**[UIView commitAnimations];**
CGRect aboutFrame = aboutView.frame;
aboutFrame.origin.x = 104; // new x coordinate
aboutFrame.origin.y = 457; // new y coordinate
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration: 1];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
aboutView.frame = aboutFrame;
**[UIView commitAnimations];**