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?
Related
I'm using scroll view in my application ,since when i click on dob text-field the datepicker view is showing as a pop up ,on further when i click in continuous text field the view is being like in the image,Here my code,
For date picker visibility.
UIDatePicker pop up after UIButton is pressed
For keyboard orientation
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
[dob resignFirstResponder];
if (txt1.textColor == [UIColor lightGrayColor]) {
txt1.text = #"";
txt1.textColor = [UIColor blackColor];
}
if ([textField isEqual:dob])
{
[self but];
[dob resignFirstResponder];
//return NO;
}
//[self animateTextField:textField up:YES];
[textField setClearButtonMode:UITextFieldViewModeWhileEditing];
CGRect textFieldRect = [self.view.window convertRect:textField.bounds fromView:textField];
CGRect viewRect = [self.view.window convertRect:self.view.bounds fromView:self.view];
CGFloat midline = textFieldRect.origin.y + 0.1 * textFieldRect.size.height;
CGFloat numerator = midline - viewRect.origin.y - MINIMUM_SCROLL_FRACTION * viewRect.size.height;
CGFloat denominator = (MAXIMUM_SCROLL_FRACTION - MINIMUM_SCROLL_FRACTION) * viewRect.size.height;
CGFloat heightFraction = numerator / denominator;
if (heightFraction < 0.0)
{
heightFraction = 0.0;
}
else if (heightFraction > 1.0)
{
heightFraction = 1.0;
}
UIInterfaceOrientation orientation =
[[UIApplication sharedApplication] statusBarOrientation];
if (orientation == UIInterfaceOrientationPortrait ||
orientation == UIInterfaceOrientationPortraitUpsideDown)
{
animatedDistance = floor(PORTRAIT_KEYBOARD_HEIGHT * heightFraction);
}
else
{
animatedDistance = floor(LANDSCAPE_KEYBOARD_HEIGHT * heightFraction);
}
CGRect viewFrame = self.view.frame;
viewFrame.origin.y -= animatedDistance;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
[self.view setFrame:viewFrame];
[UIView commitAnimations];
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
//[self animateTextField:textField up:NO];
CGRect viewFrame = self.view.frame;
viewFrame.origin.y += animatedDistance;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
[self.view setFrame:viewFrame];
[UIView commitAnimations];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
return [textField resignFirstResponder];
return [txt1 resignFirstResponder];
}
Can any one help me to clear.
You need to resize your scrollview when the key board appears.
this can be done by adding:
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:#selector(keyboardShown) name:UIKeyboardDidShowNotification object:nil];
[center addObserver:self selector:#selector(keyboardHidden) name:UIKeyboardWillHideNotification object:nil];
in the viewDidLoad.
Then define the methods keyboardShown and keyboardHidden in your implementation file.
These methods will be called automatically when keyboard appears and disappears.
In these methods resize your background view accordingly. since you are using scroll view please mind the scrollView's contectView size also. as its different from the view's frame size.
For the basic problem of having a scroll view and needing to move its contents when the keyboard appears, I have found this open source scroll view class by Michael Tyson to be very useful.
Basically, you just add the TPKeyboardAvoidingScrollView class to your project, and use it where you would normally use a UIScrollView. The child views that you add to the TPKeyboardAvoidingScrollView can be UITextField objects, if you like. When you tap those fields to begin editing, and the keyboard appears, the TPKeyboardAvoidingScrollView container will choose an appropriate scroll position so that the field that's being edited is not hidden by the keyboard, and you won't see black bars like you have in your screen shot.
I think i get the problem.
jst for example, in ur register page, many textfields and button for DOB.
So, basically when any textfield editing and after that instead of return keyboard, user press button of DOB.
so u have to first resignFirstRespoder ur all textfields.
Problem is when u startEditing frame set to top and endEditing set to bottom but when u click to button endEditing not called so frame not set to bottom. And again u startEditing frame again set to top so problem aries.
I hope this help...
I have registered for notifications of Keyboard showing and Hiding.
The text View is scrollable when not clicked on it.. i.e. when it is not in editable mode..
When user click .. i update its frame to come up ..and after that it doesn't scroll.. after ending editing.. i change its position back its scrollable again..
Here is my code
- (void)keyboardWillHide:(NSNotification *)n
{
NSDictionary* userInfo = [n userInfo];
// get the size of the keyboard
CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
// resize the scrollview
CGRect viewFrame = self.NoteTextView.frame;
// I'm also subtracting a constant kTabBarHeight because my UIScrollView was offset by the UITabBar so really only the portion of the keyboard that is leftover pass the UITabBar is obscuring my UIScrollView.
viewFrame.origin.y += (keyboardSize.height * 0.36);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
// The kKeyboardAnimationDuration I am using is 0.3
[UIView setAnimationDuration:0.1];
[UIView commitAnimations];
[self.NoteTextView setContentSize:CGSizeMake(310,580)];
[self.NoteTextView setScrollEnabled:YES];
keyboardIsShown = NO;
}
- (void)keyboardWillShow:(NSNotification *)n
{
// This is an ivar I'm using to ensure that we do not do the frame size adjustment on the UIScrollView if the keyboard is already shown. This can happen if the user, after fixing editing a UITextField, scrolls the resized UIScrollView to another UITextField and attempts to edit the next UITextField. If we were to resize the UIScrollView again, it would be disastrous. NOTE: The keyboard notification will fire even when the keyboard is already shown.
if (keyboardIsShown) {
return;
}
NSDictionary* userInfo = [n userInfo];
// get the size of the keyboard
CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
// resize the noteView
CGRect viewFrame = self.NoteTextView.frame;
// I'm also subtracting a constant kTabBarHeight because my UIScrollView was offset by the UITabBar so really only the portion of the keyboard that is leftover pass the UITabBar is obscuring my UIScrollView.
viewFrame.origin.y -= (keyboardSize.height * 0.36);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
// The kKeyboardAnimationDuration I am using is 0.3
[UIView setAnimationDuration:0.3];
[self.NoteTextView setFrame:viewFrame];
[UIView commitAnimations];
[self.NoteTextView setContentSize:CGSizeMake(310, 580)];
[self.NoteTextView setScrollEnabled:YES];
keyboardIsShown = YES;
}
I have even enabled scrolling enabled and changed its content size in the methods.
It sound really weird.
My Suggestions:
1. Check that non of its superview's UserInteractioEnable property in the new frame isn't false
2. Try this code on new and clear project.
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;
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 have an editable UITextView with a couple pages worth of text. When the user taps inside and it brings up the keyboard, it hides the bottom part of the text and you can not scroll to see it.
Is there some obvious/easy/standard way to deal with this? I assume its a common issue. I assume that you have to resize the text view when the keyboard is up, or something like that?
Also, when they tap on the text view in the bottom half of the page, how to make it automatically scroll so that the line they tapped on is visible when the keyboard appears? Or will this be automatically taken care of if i resize the text view when the keyboard appears.
Thanks a lot guys
This has been discussed extensively here: How to make a UITextField move up when keyboard is present?
I personally have used Shiun's solution in the past and it works well.
UPDATE:
If you don't want to use that method, a slightly simpler method is to resize your text field when the keyboard shows. It would be better to follow the instructions on the link I posted above as the KeyboardWillShow notification will give you access to the keyboard height.
First set the delegate of the UITextField = self. Then:
-(void)textFieldDidBeginEditing:(UITextField *)textField { // This is where the keyboard becomes visible
textField.frame = CGRectMake(textField.frame.origin.x, textField.frame.origin.y, textField.frame.size.width, textField.frame.size.height-100);
}
-(void)textFieldDidEndEditing:(UITextField *)textField { // This is where the keyboard hides itself
textField.frame = CGRectMake(textField.frame.origin.x, textField.frame.origin.y, textField.frame.size.width, textField.frame.size.height+100);
}
You can tweak the 100 depending on your orientation etc. If you wanted to add some animations you could do:
-(void)textFieldDidBeginEditing:(UITextField *)textField { // This is where the keyboard becomes visible
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDelegate:self];
[UIView setAnimationDuration:0.5];
[UIView setAnimationBeginsFromCurrentState:YES];
textField.frame = CGRectMake(textField.frame.origin.x, textField.frame.origin.y, textField.frame.size.width, textField.frame.size.height-100);
[UIView commitAnimations];
}
-(void)textFieldDidEndEditing:(UITextField *)textField { // This is where the keyboard hides itself
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDelegate:self];
[UIView setAnimationDuration:0.5];
[UIView setAnimationBeginsFromCurrentState:YES];
textField.frame = CGRectMake(textField.frame.origin.x, textField.frame.origin.y, textField.frame.size.width, textField.frame.size.height+100);
[UIView commitAnimations];
}
This will nicely scroll your UITextView to the top of the keyboard when editing starts. This will also work if your UITextView have dynamic height (autogrow/autosize when typing). Tested in iOS 7.
Call your keyboard observer method and set UITextView delegate to current class:
- (void)viewDidLoad
{
...
[self observeKeyboard];
textView.delegate = (id)self;
}
Add keyboard observer for UIKeyboardDidShowNotification and UIKeyboardWillShowNotification:
- (void)observeKeyboard
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];
}
Get keyboard size:
- (void)keyboardWillShow:(NSNotification *)notification
{
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
_keyboardHeight = keyboardSize.height;
}
- (void)keyboardDidShow:(NSNotification *)notification
{
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
_keyboardHeight = keyboardSize.height;
}
When UITextView did begin editing or value has changed call scrollKeyboardToTextView:
- (void)textViewDidBeginEditing:(UITextView *)textView
{
[self scrollKeyboardToTextView:textView];
}
- (void)textViewDidChange:(UITextView *)textView
{
[self scrollKeyboardToTextView:textView];
}
Scroll UITextView with animation to the top of the keyboard:
- (void)scrollKeyboardToTextView:(UITextView *)textView
{
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, _keyboardHeight, 0.0);
self.scrollView.contentInset = contentInsets;
self.scrollView.scrollIndicatorInsets = contentInsets;
CGRect aRect = self.view.frame;
aRect.size.height -= _keyboardHeight;
CGPoint origin = textView.frame.origin;
origin.y -= self.scrollView.contentOffset.y;
origin.y += textView.frame.size.height;
CGPoint scrollPoint = CGPointMake(0.0, textView.frame.origin.y + textView.frame.size.height - (aRect.size.height));
[self.scrollView setContentOffset:scrollPoint animated:YES];
}