Issue with TPKeyboardAvoidingScrollView - iphone

I'm using TPKeyboardAvoidingScrollView for moving view up when keyboard appears. It is working perfectly when I return my keyboard in a normal speed. But when I return the keyboard with the speed higher than normal. Then the view stuck to the top and doesn't move down.
Any idea?
Any of you have seen this kind of problem before?
Any help is appreciated!!

I solved the problem by modifying following method. Take a look at the difference here.
Before:
- (void)keyboardWillHide:(NSNotification*)notification
{
_keyboardRect = CGRectZero;
_keyboardVisible = NO;
// Restore dimensions to prior size
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationCurve:[[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
[UIView setAnimationDuration:[[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue]];
self.contentInset = _priorInset;
[self setScrollIndicatorInsets:self.contentInset];
_priorInsetSaved = NO;
[UIView commitAnimations];
}
After:
- (void)keyboardWillHide:(NSNotification*)notification
{
_keyboardRect = CGRectZero;
// Restore dimensions to prior size
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationCurve:[[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
[UIView setAnimationDuration:[[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue]];
self.contentInset = _priorInset;
[self setScrollIndicatorInsets:self.contentInset];
_priorInsetSaved = NO;
[self adjustOffsetToIdealIfNeeded];
[UIView commitAnimations];
_keyboardVisible = NO;
}

Related

UITableView won't scroll after keyboard is hidden

I have a UITableView with custom cells. Based on an answer to this question I am resizing the view when to accommodate the keyboard and resizing when the keyboard is dismissed. After dismissing the keyboard the table view no longer scrolls.
These are the methods called when showing and hiding the keyboard:
-(void)keyboardWillShow:(NSNotification *)note
{
NSDictionary* userInfo = [note userInfo];
NSValue* keyboardFrameValue = [userInfo objectForKey:#"UIKeyboardBoundsUserInfoKey"];
if (!keyboardFrameValue) {
keyboardFrameValue = [userInfo objectForKey:#"UIKeyboardFrameEndUserInfoKey"];
}
// Reduce the tableView height by the part of the keyboard that actually covers the tableView
CGRect windowRect = [[UIApplication sharedApplication] keyWindow].bounds;
CGRect viewRectAbsolute = [myTableView convertRect:myTableView.bounds toView:[[UIApplication sharedApplication] keyWindow]];
CGRect frame = myTableView.frame;
frame.size.height -= [keyboardFrameValue CGRectValue].size.height - CGRectGetMaxY(windowRect) + CGRectGetMaxY(viewRectAbsolute);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
[UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
myTableView.frame = frame;
[UIView commitAnimations];
UITableViewCell *textFieldCell = (id)((UITextField *)self.textFieldBeingEdited).superview.superview;
NSIndexPath *textFieldIndexPath = [myTableView indexPathForCell:textFieldCell];
[NSObject cancelPreviousPerformRequestsWithTarget:self];
[myTableView scrollToRowAtIndexPath:textFieldIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
}
-(void)keyboardWillHide:(NSNotification *)note
{
CGRect keyboardRect = [[[note userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
NSTimeInterval animationDuration = [[[note userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGRect frame = self.myTableView.frame;
frame.size.height += keyboardRect.size.height + 49;
[UIView beginAnimations:#"ResizeForKeyboard" context:nil];
[UIView setAnimationDuration:animationDuration];
self.myTableView.frame = frame;
[UIView commitAnimations];
myTableView.scrollEnabled = YES;
}
Any ideas what I am missing?
I've used the same question you link to to solve the same problem. It's been working great for me although I don't remember how much of the original code I ended up using.
For your problem, (though I imagine you've tried this) the first thing that comes to mind is to look in your code to see if your doing
self.tableView.scrollEnabled = NO;
and if so you should verify that you have a corresponding statement somewhere sets it back to YES; in fact you might set scrollEnabled to YES in keyboardWillHide just to test if that helps.
The problematic line is:
frame.size.height += keyboardRect.size.height + 49;
it should be:
frame.size.height += keyboardRect.size.height - self.navigationController.toolbar.frame.size.height;

How to animate a UITextView that is a subview?

I am trying to animate a UITextView (myTextView) that is a subview inside a UIScrollView (scrollView).
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlDown forView:myTextView cache:YES];
[scrollView addSubview:myTextView];
[UIView commitAnimations];
myTextView appears without animation!
What kind of animation do you want to do? If you want to fade in, for example, you have to do
[scrollView addSubview:myTextView];
myTextView.alpha = 0.0;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlDown forView:myTextView cache:YES];
myTextView.alpha = 1.0;
[UIView commitAnimations];
You can change several properties (e.g.: frame, transform) to make animations.
http://www.4shared.com/dir/-PGqZEXR/zoominzoomout.html just add this file with your project and call it through this functions
here im2 is UIVIEW and i paste image on it then passing this through view didload like this
- (void)viewDidLoad {
[self loadFlowersInView:im2];
[self.view addSubview:im2];
}
now attach this function like this
- (void) loadFlowersInView: (UIView *) backdrop {
NSString *create_button = nil; // Add the flowers to random points on the screen
for (int i = 0; i < 1; i++) {
MagPicAppDelegate *appdelegate = (MagPicAppDelegate *)[[UIApplication sharedApplication] delegate];
NSString *whichFlower = appdelegate.imageName;
UIImage *stemp = [UIImage imageNamed:#"approve.png"];
DragView *dragger = [[DragView alloc] initWithImage:stemp];
dragger.userInteractionEnabled = YES;
dragger.center = CGPointMake(160.0f, 140.0f);
[im2 addSubview:dragger];
[dragger release];
}
[self.view addSubview:im2];
[im2 release];
}

UIView Animaton Resets to beginning

I'm attempting to run an animation so that the scrollview's contentoffset gets continually scrolling down.
However, after each repeat, it will animate from the original position and it is not progressing.
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration:1.0];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationRepeatCount: 100];
CGPoint contentOffset = scrollView.contentOffset;
contentOffset.y += 50;
scrollView.contentOffset = contentOffset;
scrollView.transform = CGAffineTransformIdentity;
[UIView commitAnimations];
any ideas ?
Why are you attempting to manually scroll the view? Can't you use the method
- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated
?
Regardless, I believe the reason your animation isn't working as you expect is because you're setting a repeat count instead of actually re-rendering your animation each time. If you want to work around this problem, you could animate again in the animation callback by creating a method wrapping the animation and passing parameters via the context pointer.
- (void) animateContentOffsetByAmount:(CGFloat)amount numberRemaining:(int)num {
if (num == 0) return;
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:
#selector(scrollAnimationStoppedWithID:finished:context:)];
//NSArray released in callback
NSArray* contextArray = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:amount],
[NSNumber numberwithInt:num], nil]
[UIView beginAnimations:nil context:contextArray];
[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration:1.0];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
CGPoint contentOffset = scrollView.contentOffset;
contentOffset.y += amount;
scrollView.contentOffset = contentOffset;
scrollView.transform = CGAffineTransformIdentity;
[UIView commitAnimations];
}
- (void) scrollAnimationStoppedWithID:(NSString*)id
finished:(NSNumber*)finished context:(void*)context {
NSArray* contextArray = (NSArray*)context;
CGFloat amount = [(NSNumber*)[contextArray objectAtIndex:0] floatValue];
int count = [(NSNumber*)[contextArray objectAtIndex:1] intValue];
count = count - 1;
[contextArray release];
[self animateContentOffsetByAmount:amount numberRemaining:count]
}
Then in your code, just call
[self animateContentOffsetByAmount:50 numberRemaining:100];

Hiding keyboard with UIScrollView without glitches

I have multiple editable textfiels and some of them are covered with keyboard. So I used UIScrollView and it works quite nice.
Problem is when I want to hide keyboard. If I was scrolled down, after the keyboard hides, everything jumps up as it was at beginning (without keyboard). I want to tween this part as the keyboard is hiding.
So far I got this code (2 methods for keyboard events):
-(void)keyboardWillShow:(NSNotification *)notif{
if(keyboardVisible)
return;
keyboardVisible = YES;
NSDictionary* info = [notif userInfo];
NSValue* value = [info objectForKey:UIKeyboardBoundsUserInfoKey];
CGSize keyboardSize = [value CGRectValue].size;
CGRect viewFrame = self.view.frame;
viewFrame.size.height -= keyboardSize.height;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.3];
[scrollView setFrame:viewFrame];
[UIView commitAnimations];
}
- (void)keyboardWillHide:(NSNotification *)notif{
if(!keyboardVisible)
return;
keyboardVisible = NO;
NSDictionary* info = [notif userInfo];
NSValue* value = [info objectForKey:UIKeyboardBoundsUserInfoKey];
CGSize keyboardSize = [value CGRectValue].size;
CGRect viewFrame = self.view.frame;
viewFrame.size.height += keyboardSize.height;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.3];
[scrollView setFrame:viewFrame];
[UIView commitAnimations];
}
It works pretty well with hiding keyboard but unfortunately it doesn't work when user switches from one text field to another. It will fire keyboardWillHide and keyboardWillShow events, one right after another. This will result in two animations, second one interrupting the first one. It doesn't look good.
Problem is with keyboardWillHide firing even when keyboard will not hide. At that point I don't know if keyboard will be shown again or not.
I also tried it with UIScrollView scrollRectToVisible and setContentOffset methods.. but they resulted in glitches when keyboard was hiding.
use this method to handle multiple text field and keyboard
-(void)scrollViewToCenterOfScreen:(UIView *)theView
{
CGFloat viewCenterY = theView.center.y;
CGRect applicationFrame = [[UIScreen mainScreen] applicationFrame];
CGFloat availableHeight = applicationFrame.size.height - 200; // Remove area covered by keyboard  
CGFloat y = viewCenterY - availableHeight / 2.0;
if (y < 0) {
y = 0;
}
[scrollview setContentOffset:CGPointMake(0, y) animated:YES];
}
call it in textfield delegate=
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
[self scrollViewToCenterOfScreen:textField];
}
and set scroll view frame in the below textfield delegate=
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
[self.scrollview setContentOffset:CGPointMake(0, 0) animated:YES];
return YES;
}
Why not use boolean values to indicate whether it is an appearance or just changing?

move up UIToolbar

I have a UIToolbar at bottom of my view, and I have a UITextField in this toolbar. When I begin editing this field, it is hidden behind the keyboard. To see what I've typed, I want to move the toolbar up at the moment the keyboard is presented (and then move it back down when I've finished editing).
How do I move this UIToolbar up/down?
add your viewController class to the list of observers of UIKeyboardWillShowNotification/UIKeyboardWillHideNotification. then you can move your view to make your textView visible. You can also get animation parameters from this notifications to synchronize your animation with keyboard animation parameters of the current OS version. this code I've used for paging
- (void) viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(liftMainViewWhenKeybordAppears:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(returnMainViewToInitialposition:) name:UIKeyboardWillHideNotification object:nil];
}
- (void) viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
in the methods below I set two methods to handle keyboard notifications. and here are this methods:
- (void) liftMainViewWhenKeybordAppears:(NSNotification*)aNotification{
NSDictionary* userInfo = [aNotification userInfo];
NSTimeInterval animationDuration;
UIViewAnimationCurve animationCurve;
CGRect keyboardFrame;
[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
[[userInfo objectForKey:UIKeyboardBoundsUserInfoKey] getValue:&keyboardFrame];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];
[self.view setFrame:CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y - keyboardFrame.size.height, self.view.frame.size.width, self.view.frame.size.height)];
[UIView commitAnimations];
}
- (void) returnMainViewToInitialposition:(NSNotification*)aNotification{
NSDictionary* userInfo = [aNotification userInfo];
NSTimeInterval animationDuration;
UIViewAnimationCurve animationCurve;
CGRect keyboardFrame;
[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
[[userInfo objectForKey:UIKeyboardBoundsUserInfoKey] getValue:&keyboardFrame];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];
[self.view setFrame:CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y + keyboardFrame.size.height, self.view.frame.size.width, self.view.frame.size.height)];
[UIView commitAnimations];
}
Thanks that worked!
Here is a slight improvement:
- (void) liftMainViewWhenKeybordAppears:(NSNotification*)aNotification{
[self scrollViewForKeyboard:aNotification up:YES];
}
- (void) returnMainViewToInitialposition:(NSNotification*)aNotification{
[self scrollViewForKeyboard:aNotification up:NO];
}
- (void) scrollViewForKeyboard:(NSNotification*)aNotification up: (BOOL) up{
NSDictionary* userInfo = [aNotification userInfo];
// Get animation info from userInfo
NSTimeInterval animationDuration;
UIViewAnimationCurve animationCurve;
CGRect keyboardFrame;
[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
[[userInfo objectForKey:UIKeyboardBoundsUserInfoKey] getValue:&keyboardFrame];
// Animate up or down
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];
[self.view setFrame:CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y + (keyboardFrame.size.height * (up?-1:1)), self.view.frame.size.width, self.view.frame.size.height)];
[UIView commitAnimations];
}
Building on the answers above and using the convenience method [UIView animateWithDuration...]. Observe the will show/hide keyboard notifications and use these handlers.
- (void)keyboardWillShow:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
NSNumber *durationValue = info[UIKeyboardAnimationDurationUserInfoKey];
NSNumber *curveValue = info[UIKeyboardAnimationCurveUserInfoKey];
NSValue *endFrame = info[UIKeyboardFrameEndUserInfoKey];
[UIView animateWithDuration:durationValue.doubleValue
delay:0
options:(curveValue.intValue << 16)
animations:^{
self.navigationController.toolbar.frame = CGRectMake(0,
[endFrame CGRectValue].origin.y - self.navigationController.toolbar.bounds.size.height,
self.navigationController.toolbar.bounds.size.width,
self.navigationController.toolbar.bounds.size.height);
}
completion:nil];
}
- (void)keyboardWillHide:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
NSNumber *durationValue = info[UIKeyboardAnimationDurationUserInfoKey];
NSNumber *curveValue = info[UIKeyboardAnimationCurveUserInfoKey];
[UIView animateWithDuration:durationValue.doubleValue
delay:0
options:(curveValue.intValue << 16)
animations:^{
self.navigationController.toolbar.frame = CGRectMake(0,
self.view.bounds.size.height - self.navigationController.toolbar.bounds.size.height,
self.navigationController.toolbar.bounds.size.width,
self.navigationController.toolbar.bounds.size.height);
}
completion:nil];
}
Thank you so much for this; it works great. However, the code as presented has 2 limitations as I experienced them:
1) The view being repositioned simply slides up out of the screen rather than resizing to fit the space available after the keyboard appears
2) Repeat notifications due to switching text fields continue to apply the frame change, causing the view to incrementally fly off the screen.
The cause is that the above is a reposition relative to the view's current frame rather than a resize relative to the keyboard. Here are two amended lines of code which fix this:
In liftMainViewWhenKeybordAppears:, resize rather than reposition, relative to the keyboard:
keyboardFrame = [self.view.window convertRect:keyboardFrame toView:self.view.superview];
CGRect superviewFrame = [self.view.window convertRect:self.view.superview.frame toView:self.view];
[self.view setFrame:CGRectMake(self.view.frame.origin.x,
self.view.frame.origin.y,
self.view.frame.size.width,
superviewFrame.size.height - keyboardFrame.size.height)];
In returnMainViewToInitialposition:, change the animation to this setFrame: (essentially akin to the identity transform).
[self.view setFrame:CGRectMake(self.view.frame.origin.x,
self.view.frame.origin.y,
self.view.frame.size.width,
keyboardFrame.origin.y + keyboardFrame.size.height)];
Here is a more elegant solution using uiview category
#import <Foundation/Foundation.h>
#interface UIView(AnimationUtils)
-(void)scrollControlToCenter:(UIView *)view;
-(void)scrollViewToOriginalPosition;
#end
#import "UIView+AnimationUtils.h"
#implementation UIView(AnimationUtils)
#pragma mark ScrollView Methods
//Method Called whenever keyboard appears
- (void)scrollControlToCenter:(UIView *)view {
if([view isKindOfClass:[UITextField class]]){
CGRect viewFrame = [view frame];
float verticalDistance = 216.0f - viewFrame.origin.y - (2*viewFrame.size.height);
if(viewFrame.size.height >= (460 - 216)/2){
verticalDistance = 0;
}
[UIView beginAnimations:#"ScrollToCenter" context:nil];
[UIView setAnimationDuration:0.5];
[self setFrame:CGRectMake(0, verticalDistance, self.frame.size.width, self.frame.size.height)];
[UIView commitAnimations];
}else if([view isKindOfClass:[UITextView class]]){
[UIView beginAnimations:#"ScrollToTop" context:nil];
[UIView setAnimationDuration:0.5];
UIView *viewBG = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
[viewBG setTag:5];
[viewBG setBackgroundColor:[UIColor blackColor]];
[viewBG setAlpha:0.75];
[self addSubview:viewBG];
[view setFrame:CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, view.frame.size.height)];
[self setFrame:CGRectMake(0, -view.frame.origin.y , self.frame.size.width, self.frame.size.height)];
[self insertSubview:view atIndex:[self.subviews count] + 1];
[UIView commitAnimations];
}
}
-(void)scrollViewToOriginalPosition{
[UIView beginAnimations:#"ScrollToOriginal" context:nil];
[UIView setAnimationDuration:0.5];
for(UIView *view in self.subviews){
if(view.tag == 5){
[view removeFromSuperview];
}
}
[self setFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
[UIView commitAnimations];
}
#pragma mark -
#end