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;
}
How to get a keyboard size to resize UITextView and how to use UIKeyboardFrameEndUserInfoKey with Japanese keyboard? The following code to resize UITextView works good on a standard keyboard. But doesn't work with Japanese. How to fix it?
- (void)keyboardWillShow:(NSNotification *)aNotification {
[self moveTextViewForKeyboard:aNotification up:YES];
}
- (void)keyboardWillHide:(NSNotification *)aNotification {
[self moveTextViewForKeyboard:aNotification up:NO];
}
- (void) moveTextViewForKeyboard:(NSNotification*)aNotification up: (BOOL) up
{
NSDictionary* userInfo = [aNotification userInfo];
// Get animation info from userInfo
NSTimeInterval animationDuration;
UIViewAnimationCurve animationCurve;
CGRect keyboardEndFrame;
[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];
// Animate up or down
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];
CGRect newFrame = textView.frame;
CGRect keyboardFrame = [self.view convertRect:keyboardEndFrame toView:nil];
newFrame.size.height -= keyboardFrame.size.height * (up? 1 : -1);
textView.frame = newFrame;
[UIView commitAnimations];
}
Thanks a lot for the help!
The correct fragment of the code:
CGRect newFrame = editSource.frame;
CGRect keyboardFrame = [self.view convertRect:keyboardEndFrame toView:nil];
keyboardFrame.size.height -= tabBarController.tabBar.frame.size.height;
if (up) {
editHeight = newFrame.size.height;
newFrame.size.height -= keyboardFrame.size.height;
} else {
newFrame.size.height = editHeight;
}
editSource.frame = newFrame;
WARNIGN!
The method is obsolete. The correct answer is located here: How can I add support for Chinese keyboard with UITextView on iOS 7?
am using scrollview for text field when i press that text field the view scrolling down can anyone pls help me why its happening ?
This code am using for scroll
- (void)keyboardWasShown:(NSNotification*)aNotification {
if (keyboardShown)
return;
//static const float deviceHeight = 480;
static const float keyboardHeight = 216;
static const float gap = 5; //gap between the top of keyboard and the control
//Find the controls absolute position in the 320*480 window - it could be nested in other views
CGPoint absolute = [activeField.superview convertPoint:activeField.frame.origin toView:nil];
//NSLog(#"Keyborad Shown %f : %f",absolute.y,(keyboardHeight + gap);
if (absolute.y > (keyboardHeight + gap)) {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.3f]; //this is speed of keyboard
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
CGRect bkgndRect = activeField.superview.frame;
bkgndRect.size.height += kbSize.height;
[activeField.superview setFrame:bkgndRect];
[scrollview setContentOffset:CGPointMake(0.0, activeField.frame.origin.y-92) animated:YES];
[UIView commitAnimations];
}
keyboardShown = YES;
}
// Called when the UIKeyboardDidHideNotification is sent
- (void)keyboardWasHidden:(NSNotification*)aNotification {
//[UIView beginAnimations:nil context:nil];
//[UIView setAnimationDuration:0.003f]; //this is speed of keyboard
NSDictionary* info = [aNotification userInfo];
// Get the size of the keyboard.
NSValue* aValue = [info objectForKey:UIKeyboardFrameEndUserInfoKey];
CGSize keyboardSize = [aValue CGRectValue].size;
// Reset the height of the scroll view to its original value
CGRect viewFrame = [scrollview frame];
viewFrame.size.height += keyboardSize.height;
scrollview.frame = viewFrame;
//[UIView commitAnimations];
keyboardShown = NO;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField {
activeField = textField;
}
Try This....
This code my be helpful for you to scroll your scrollview up.
(BOOL)textViewShouldBeginEditing:(UITextView *)textView {
[scrView setContentOffset:CGPointMake(0, textView.frame.origin.y - 20)];
return YES;
}
I've a serious problem, and I cannot solve it by myself. I've spent hours searching the documentations, programming guides as well as developer forums and stack overflow.
The problem is I want to display a picker view in UITableViewController. I have a screen that has multiple text fields allowing me to search by title/author/keywords... and I'd also like to specify the minimum and maximum dates, using the UIDatePicker (or UIPickerView - to specify "last 5 days" for example).
I want to use UITableViewController because it saves me a lot of time resizing the table while the keyboard pops up when user presses the text field. In fact I've never been able to reproduce this animation using UIViewController and listening to textfields' delegate. It was almost perfect but there were some visible disadvantages comparing to the behaviour of table if displayed using UITableViewController.
So everything's fine when there are only textfields. But what about the date fileds? I want to make it exactly like the Contacts.app by Apple when I want to add a new contact and specify the birthday. In that application the Date Picker is shown, the table is resized, switching between email/phone field and birthday works great. I could believe that the date picker is in this case the keyboard but not for typing phone/email but date because it slides in/out just like a keyboard and is replaced instantly when the keyboard/picker is opened.
How did thet accomplished it?
Or where can I find the easiest solution to reproduce it. I believe it cannot be as hard because it's very common situation.
Regards
Chris
All of that is pointless. We should deal with the inputView and inputAccessoryView, where inputView should has the picker and inputAccessoryView the toolbar.
You're going to have to create a UIWindow object, then add a view. The windowLevel property makes it higher than the statusBar, which you may or may not want.
//statusWindow is a UIWindow ivar declared in the header
//pickerShowing is declared as a BOOL in header
//release and removeFromSuperview is done in the animation delegate methods
//ANIMATE IN
-(void)slideIn {
CGRect pickerFrame = CGRectMake(0.0f, 0.0f, 320.0f, 200.0f); //guessing on height
UIView *viewForPicker = [[UIView alloc] init];
UIPickerView *aPicker = [[UIPickerView alloc] init]; //don't forget to set delegate and dataSource
viewForPicker.frame = pickerFrame;
statusWindow = [[UIWindow alloc] initWithFrame:CGRectMake(0.0, 480.0, 320.0f, 200.0f)];//guessing on height, y value is off the screen (bottom)
statusWindow.windowLevel = UIWindowLevelStatusBar;
statusWindow.hidden = NO;
statusWindow.backgroundColor = [UIColor clearColor];
[statusWindow makeKeyAndVisible];
[viewForPicker addSubview:aPicker];
[statusWindow addSubview:viewForPicker];
[viewForPicker release];
[aPicker release];
[UIView beginAnimations:#"slideUp" context:nil];
[UIView setAnimationDuration:0.3];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(animationFinished:)];
statusWindow.frame = CGRectMake(0.0f, 200.0f, 320.0f, 200.0f); //guessing on y and height values, change them to suit needs
[UIView commitAnimations];
pickerShowing = YES;
}
//ANIMATE out:
-(void)slideOut {
[UIView beginAnimations:#"slideDown" context:nil];
[UIView setAnimationDuration:0.3];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(animationFinished:)];
statusWindow.frame = CGRectMake(0.0f, 480.0f, 320.0f, 200.0f);
[UIView commitAnimations];
pickerShowing = NO;
}
-(void)animationFinished:(NSString *)name {
if ([name isEqualToString:#"slideDown"]) {
[statusWindow release];
}
}
If you want to slide in/out the picker view, you can use Core Animation.
Simplest snippet:
// Slide picker view in
[UIView beginAnimations: #"SlideIn" context: nil];
myPickerView.frame = upFrame;
[UIView commitAnimations];
// ...
// Slide picker view out
[UIView beginAnimations: #"SlideOut" context: nil];
myPickerView.frame = downFrame;
[UIView commitAnimations];
upFrame and downFrame are CGRect you make with the right position for your picker view on screen and off screen respectively.
Hope this helps.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *targetCell = [tableView cellForRowAtIndexPath:indexPath];
self.pickerView.date = [self.dateFormatter dateFromString:targetCell.detailTextLabel.text];
// check if our date picker is already on screen
if (self.pickerView.superview == nil)
{
[self.view.window addSubview: self.pickerView];
// size up the picker view to our screen and compute the start/end frame origin for our slide up animation
//
// compute the start frame
CGRect screenRect = [[UIScreen mainScreen] applicationFrame];
CGSize pickerSize = [self.pickerView sizeThatFits:CGSizeZero];
CGRect startRect = CGRectMake(0.0,
screenRect.origin.y + screenRect.size.height,
pickerSize.width, pickerSize.height);
self.pickerView.frame = startRect;
// compute the end frame
CGRect pickerRect = CGRectMake(0.0,
screenRect.origin.y + screenRect.size.height - pickerSize.height,
pickerSize.width,
pickerSize.height);
// start the slide up animation
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
// we need to perform some post operations after the animation is complete
[UIView setAnimationDelegate:self];
self.pickerView.frame = pickerRect;
// shrink the table vertical size to make room for the date picker
CGRect newFrame = self.tableView.frame;
newFrame.size.height -= self.pickerView.frame.size.height;
self.tableView.frame = newFrame;
[UIView commitAnimations];
// add the "Done" button to the nav bar
self.navigationItem.rightBarButtonItem = self.doneButton;
}
}
- (void)slideDownDidStop
{
// the date picker has finished sliding downwards, so remove it
[self.pickerView removeFromSuperview];
}
- (IBAction)dateAction:(id)sender
{
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
cell.detailTextLabel.text = [self.dateFormatter stringFromDate:self.pickerView.date];
}
- (IBAction)doneAction:(id)sender
{
CGRect screenRect = [[UIScreen mainScreen] applicationFrame];
CGRect endFrame = self.pickerView.frame;
endFrame.origin.y = screenRect.origin.y + screenRect.size.height;
// start the slide down animation
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
// we need to perform some post operations after the animation is complete
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(slideDownDidStop)];
self.pickerView.frame = endFrame;
[UIView commitAnimations];
// grow the table back again in vertical size to make room for the date picker
CGRect newFrame = self.tableView.frame;
newFrame.size.height += self.pickerView.frame.size.height;
self.tableView.frame = newFrame;
// remove the "Done" button in the nav bar
self.navigationItem.rightBarButtonItem = nil;
// deselect the current table row
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
}
You can download a full working sample app from Apple demonstrating just this.
http://developer.apple.com/library/ios/#samplecode/DateCell/Introduction/Intro.html
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?