UIView.animateWithDuration not animating when called inside keyboardWillShow - objective-c

For some reason my view is not animating:
- (void)keyboardWillShow:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
double duration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
int curve = [[info objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue];
int height = self.view.bounds.size.height - kbSize.height+self.tabBarController.tabBar.frame.size.height;
self.notesView.frame = CGRectMake(0, -height,
self.view.bounds.size.width, height);
[UIView animateWithDuration:1.5 delay:0 options:curve animations:^{
self.notesView.frame = CGRectMake(0, 0, self.view.bounds.size.width, height);
} completion:nil];
}
The notesView is being displayed but not animated. When I move the animation code into a btnPressed method then it animates as expected. Any ideas?
Edit
It looks like the method is being called twice (that's a separate problem dealing with the inputAccessoryView that I still need to figure out). I updated it to see if calling the animateWithDuration code only once would solve the problem. However, it's still not animating.
- (void)keyboardWillShow:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
int curve = [[info objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue];
int height = self.view.bounds.size.height - kbSize.height + self.tabBarController.tabBar.frame.size.height;
if (height == 510) return; //for some reason the self.view.bounds.size.height is different between the two calls
self.notesView.frame = CGRectMake(0, -height, self.view.bounds.size.width, height);
[UIView animateWithDuration:1.5 delay:0 options:curve animations:^{
self.notesView.frame = CGRectMake(0, 0, self.view.bounds.size.width, height);
} completion:nil];
}

Related

UIView animation and transform cause a weird position offset

http://childhoodgamedev.qiniudn.com/xincheng_testGif.gif
UILabel* label = [[UILabel alloc] initWithFrame:CGRectMake(250, 250, 200, 100)];
label.text = #"Hello world!";
label.textColor = [UIColor blackColor];
label.textAlignment = NSTextAlignmentLeft;
label.backgroundColor = [UIColor clearColor];
label.font = [UIFont systemFontOfSize:25];
[self.view addSubview:label];
CGAffineTransform transform = CGAffineTransformIdentity;
label.transform = CGAffineTransformScale(transform, 2, 2);
[UIView animateWithDuration:4.0 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
label.transform = CGAffineTransformTranslate(label.transform, -100, 0);
} completion:^(BOOL finished) {
if (finished) {
NSLog(#"label %f %f %f %f", label.frame.origin.x, label.frame.origin.y, label.frame.size.width, label.frame.size.height);
[UIView animateWithDuration:3.0 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
NSLog(#"label %f %f %f %f", label.frame.origin.x, label.frame.origin.y, label.frame.size.width, label.frame.size.height);
label.transform = CGAffineTransformTranslate(label.transform, 100, 0);
} completion:NULL];
}
}];
There is UILabel instance named label, it's scaled to 2 ratio by CGAffineTransformScale. Then it moves from right to left, when the animation is completed, then it moves from left to right.
But the strange point is: It looks not the same position, which is the end point of animation(right to left), the start point of animation(left to right). But the NSLog tells me, they are in the same position.
http://childhoodgamedev.qiniudn.com/xincheng_QQ20150306-1.png
When I comment the state label.transform = CGAffineTransformScale(transform, 2, 2);, everything is fine. When the label change direction to move, the end position of right->left animation is just the start position of left->right animation.
So I think the problem is caused by CGAffineTransformScale. Any ideas?

UILabel animating frame change disregarding delay

I have a UILabel that I show / hide. I want to show the label, pause for a few seconds and hide it. This code ISN'T working. It removes the view as soon as the animation finished (instantly)
-(void) show
{
[UIView animateWithDuration:.5f delay:0.0f
options:UIViewAnimationOptionCurveEaseIn animations:^{
CGRect newFrame = CGRectMake(0.0f, 64.0f, [UIScreen mainScreen].bounds.size.width, 44.0f);
self.frame = newFrame;
} completion:^(BOOL finished){
[self hideAndRemove];
}];
}
-(void) hideAndRemove
{
[UIView animateWithDuration:.5f delay:2.0f
options:UIViewAnimationOptionCurveEaseIn animations:^{
CGRect frame = CGRectMake(0.0f, 64.0f, [UIScreen mainScreen].bounds.size.width, 0.0f);
self.frame = frame;
} completion:^(BOOL finished){
// nothing
}];
}
However, if I try some other animation on the frame, the delay works and the frame change is animated:
-(void) show
{
[UIView animateWithDuration:.5f delay:0.0f
options:UIViewAnimationOptionCurveEaseIn animations:^{
CGRect newFrame = CGRectMake(0.0f, 64.0f, [UIScreen mainScreen].bounds.size.width, 44.0f);
self.frame = newFrame;
} completion:^(BOOL finished){
[self hideAndRemove];
}];
}
-(void) hideAndRemove
{
[UIView animateWithDuration:.5f delay:2.0f
options:UIViewAnimationOptionCurveEaseIn animations:^{
CGRect frame = CGRectMake(0.0f, 64.0f, [UIScreen mainScreen].bounds.size.width, 250.0f);
self.frame = frame;
} completion:^(BOOL finished){
// nothing
}];
}
I don't know what the problem might be, but I think it comes from the frame height who shouldn't be set to 0.
Why not using [UILabel setAlpha:0] to hide your label, and [UILabel setAlpha:1] to show it back ? It seems cleaner than changing its frame height to 0, and it animates nicely.

Recreating the iMessage app [duplicate]

This question already has answers here:
Programmatically align a toolbar on top of the iPhone keyboard
(7 answers)
Closed 9 years ago.
I am doing a messaging app and I am trying to duplicate the toolbar on top of the key board with the UITextField and two buttons (camera and done). I know how to put a toolbar on top of the keyboard when you click on a UITextField in the view, but my textfield is on my toolbar. When the UITextField on the toolbar is clicked, I want the keyboard to come up under it and kind of push the toolbar up with it. I also need them to go down together as if they are one thing (like it does in the iMessage app). I have looked up many tutorials but cannot seem to find the answer. What code do I need to do this?? Thank you I AM NOT ASKING HOW TO PUT A TOOLBAR ON TOP OF A KEYBOARD, I AM ASKING HOW TO TRIGGER THE KEYBOARD TO COME UP UNDER THE EXISTING TOOLBAR AND BE TRIGGERED BY THE TEXTVIEW INSIDE SAID TOOLBAR
i have written this code duplicate the effect of iMessage, it uses a open source textview HPGrowingTextView
- (void)organizeView {
textView = [[HPGrowingTextView alloc] initWithFrame:CGRectMake(8, 5, 230, 40)];
textView.contentInset = UIEdgeInsetsMake(0, 5, 0, 5);
textView.minNumberOfLines = 1;
textView.maxNumberOfLines = 4;
// you can also set the maximum height in points with maxHeight
// textView.maxHeight = 200.0f;
textView.returnKeyType = UIReturnKeySend; //just as an example
textView.delegate=self;
textView.font = [UIFont systemFontOfSize:15.0f];
textView.delegate = self;
textView.internalTextView.scrollIndicatorInsets = UIEdgeInsetsMake(5, 0, 5, 0);
textView.backgroundColor = [UIColor whiteColor];
textView.placeholder = #"Type your Comment here..";
[textView becomeFirstResponder];
UIImage *rawEntryBackground = [UIImage imageNamed:#""];
UIImage *entryBackground = [rawEntryBackground stretchableImageWithLeftCapWidth:13 topCapHeight:22];
UIImageView *entryImageView = [[UIImageView alloc] initWithImage:entryBackground];
entryImageView.frame = CGRectMake(5, 0, 248, 40);
entryImageView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
UIImage *rawBackground = [UIImage imageNamed:#"message-strip.png"];
UIImage *background = [rawBackground stretchableImageWithLeftCapWidth:13 topCapHeight:22];
UIImageView *imageView = [[UIImageView alloc] initWithImage:background];
imageView.frame = CGRectMake(0, 0, _containerView.frame.size.width, _containerView.frame.size.height);
imageView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
textView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
// view hierachy
[_containerView addSubview:imageView];
[_containerView addSubview:textView];
[_containerView addSubview:entryImageView];
UIImage *sendBtnBackground = [[UIImage imageNamed:#"send"] stretchableImageWithLeftCapWidth:13 topCapHeight:0];
UIButton *doneBtn = [UIButton buttonWithType:UIButtonTypeCustom];
doneBtn.frame = CGRectMake(_containerView.frame.size.width - 69, 8, 63, 27);
doneBtn.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin;
[doneBtn setImage:sendBtnBackground forState:UIControlStateNormal];
[doneBtn addTarget:self action:#selector(postButtonAction:) forControlEvents:UIControlEventTouchUpInside];
[_containerView addSubview:doneBtn];
_containerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
}
-(void)resignTextView
{
[textView resignFirstResponder];
}
//Code from Brett Schumann
-(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];
NSInteger kbSizeH = keyboardBounds.size.height;
// get a rect for the textView frame
CGRect containerFrame = _containerView.frame;
containerFrame.origin.y -= kbSizeH-50;
////reset the table container view height
CGRect tableContainerFrame=_viewTable.frame;
tableContainerFrame.size.height=self.view.frame.size.height-(kbSizeH+containerFrame.size.height );
//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;
_viewTable.frame=tableContainerFrame;
// commit animations
[UIView commitAnimations];
}
-(void) keyboardWillHide:(NSNotification *)note{
NSNumber *duration = [note.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey];
NSNumber *curve = [note.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey];
// get a rect for the textView frame
CGRect containerFrame = _containerView.frame;
containerFrame.origin.y = self.view.bounds.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];
}
- (void)growingTextView:(HPGrowingTextView *)growingTextView willChangeHeight:(float)height
{
float diff = (growingTextView.frame.size.height - height);
CGRect r = _containerView.frame;
r.size.height -= diff;
r.origin.y += diff;
_containerView.frame = r;
}
-(BOOL)growingTextViewShouldReturn:(HPGrowingTextView *)growingTextView{
if (growingTextView == self->textView) {
[self performSelector:#selector(postButtonAction:)];
return NO;
}
else
return YES;
}

Setting UIView Frame

I'm trying to resize my UITextView when the keyboard appears, but I don't know what I'm doing wrong.
I have these three lines of code called when the keyboard appears:
CGSize kbSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
textView.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height-kbSize.height);
NSLog(#"%f,%f,%f,%f", textView.frame.origin.x, textView.frame.origin.y, textView.frame.size.width, textView.frame.size.height);
For some really odd reason my keyboard doesn't appear and here is what is logged:
0.000000,-180.000000,480.000000,180.000000
Why is the CGRects y origin getting set to -180 when it is hardcoded in at 0?
EDIT: textView is a UITextView I created programatically. I didn't use Interface Builder.
EDIT2: It seems that the problem is that the view is autoresizing when rotated.
You can try this :
- (void) moveTextViewForKeyboard:(NSNotification*)aNotification up:(BOOL)up {
NSDictionary* userInfo = [aNotification userInfo];
NSTimeInterval animationDuration;
UIViewAnimationCurve animationCurve;
CGRect keyboardEndFrame;
[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];
CGRect newFrame = textView.frame;
CGRect keyboardFrame = [self.view convertRect:keyboardEndFrame toView:nil];
keyboardFrame.size.height -= tabBarController.tabBar.frame.size.height;
newFrame.size.height -= keyboardFrame.size.height * (up?1:-1);
textView.frame = newFrame;
[UIView commitAnimations];
}
Hope it'll help

iPhone SDK: TextView, Keyboard in Landscape mode

How do I make sure that the textview is shown and the keyboard is not obscuring the textview, while in landscape.
Using UICatalog I created a TextViewController which works. In it there are two methods for calling the keyboard and making sure that textView is positioned above the keyboard. his just works great in Portrait mode.
I got the Landscape mode working, but on the textView is still being put to the top of the iPhone to compensate for the keyboard in portrait mode.
I changed the methods for showing the keyboards.
Below is the code for this methods: (I will just let see the code for show, since the hide code will be the reverse..
- (void)keyboardWillShow:(NSNotification *)aNotification
{
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
if (orientation == UIInterfaceOrientationPortrait) {
// the keyboard is showing so resize the table's height
CGRect keyboardRect = [[[aNotification userInfo] objectForKey:UIKeyboardBoundsUserInfoKey] CGRectValue];
NSTimeInterval animationDuration = [[[aNotification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGRect frame = self.view.frame;
frame.size.height -= keyboardRect.size.height;
[UIView beginAnimations:#"ResizeForKeyboard" context:nil];
[UIView setAnimationDuration:animationDuration];
self.view.frame = frame;
[UIView commitAnimations];
} else if (orientation == UIInterfaceOrientationLandscapeLeft) {
NSLog(#"Left"); // Verijderen later
CGRect keyboardRect = [[[aNotification userInfo] objectForKey:UIKeyboardBoundsUserInfoKey] CGRectValue];
NSTimeInterval animationDuration = [[[aNotification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGRect frame = self.view.frame;
frame.size.width -= keyboardRect.size.height;
[UIView beginAnimations:#"ResizeForKeyboard" context:nil];
[UIView setAnimationDuration:animationDuration];
self.view.frame = frame;
[UIView commitAnimations];
} else if (orientation == UIInterfaceOrientationLandscapeRight){
NSLog(#"Right"); // verwijderen later.
CGRect keyboardRect = [[[aNotification userInfo] objectForKey:UIKeyboardBoundsUserInfoKey] CGRectValue];
NSTimeInterval animationDuration = [[[aNotification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGRect frame = self.view.frame;
frame.size.width -= keyboardRect.size.width;
[UIView beginAnimations:#"ResizeForKeyboard" context:nil];
[UIView setAnimationDuration:animationDuration];
self.view.frame = frame;
[UIView commitAnimations];
}
}
I know that I have to change the line frame.size.height -= keyboardRect.size.height but I do not seem to get it working.
I tried frame.size.width -= keyboardRect.size.height that did not work. Losing the keyboardRect and frame all together work, however off course the keyboard obscures the textview........
I found the above code wouldn't work when in Landscape Mode on iPad
Note: I am moving all Fields, as in my case that's what i needed :-)
- (void)keyboardWillShow:(NSNotification*)aNotification {
// Only do for Landscape Mode
if (UIInterfaceOrientationIsLandscape([self interfaceOrientation])){
NSDictionary *info = [aNotification userInfo];
NSValue *aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
CGSize keyboardSize = [aValue CGRectValue].size;
NSTimeInterval animationDuration = 0.300000011920929;
CGRect frame = self.view.frame;
frame.origin.x -= keyboardSize.height-44;
frame.origin.y -= keyboardSize.height-44;
frame.size.height += keyboardSize.height-44;
[UIView beginAnimations:#"ResizeForKeyboard" context:nil];
[UIView setAnimationDuration:animationDuration];
self.view.frame = frame;
[UIView commitAnimations];
viewMoved = YES;
}
keyboardInUse = YES;
}
- (void)keyboardWillHide:(NSNotification*)aNotification {
if (UIInterfaceOrientationIsLandscape([self interfaceOrientation])){
if (viewMoved) {
NSDictionary *info = [aNotification userInfo];
NSValue *aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
CGSize keyboardSize = [aValue CGRectValue].size;
NSTimeInterval animationDuration = 0.300000011920929;
CGRect frame = self.view.frame;
frame.origin.y += keyboardSize.height-44;
frame.origin.x += keyboardSize.height-44;
frame.size.height -= keyboardSize.height-44;
[UIView beginAnimations:#"ResizeForKeyboard" context:nil];
[UIView setAnimationDuration:animationDuration];
self.view.frame = frame;
[UIView commitAnimations];
viewMoved = NO;
}
}
keyboardInUse = NO;
}
If you think you need different code for the different orientations, you're doing something else wrong. Once the orientation has changed and your superview has responded, the value that needs changing should always be the frame's height.
Here is a code that I use for this purpose. It works on both iPad and iPhone is landscape and portrait modes (inspired by a code from Apple documentation):
// Call this method somewhere in your view controller setup code.
- (void)registerForKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification object:nil];
}
// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
float offset;
if UIInterfaceOrientationIsPortrait(self.interfaceOrientation)
offset = kbSize.height;
else
offset = kbSize.width;
[UIView animateWithDuration:0.5
animations:^{
CGRect frameTxtField = myTextField.frame;
frameTxtField.origin.y -= offset;
myTextField.frame = frameTxtField;
}
];
}
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
float offset;
if UIInterfaceOrientationIsPortrait(self.interfaceOrientation)
offset = kbSize.height;
else
offset = kbSize.width;
[UIView animateWithDuration:0.5
animations:^{
CGRect frameTxtField = myTextField.frame;
frameTxtField.origin.y += offset;
myTextField.frame = frameTxtField;
}
];
}
Don't forget to call the registerForKeyboardNotifications method (e.g., in viewDidLoad).