The app I am building has a messaging/chat view controller that has a view with a textView and a button at the base of the view (tab bar is set to hidden). When the view loads, the view with those objects (the textView and the button) in it is at the base of the screen (like how it looks in the iMessage app when you go into a conversation)
Now when the textview is tapped on, obviously the keyboard moves up, and along with that I have managed to get the view to move up and sit right up on top of the keyboard (like when you go to type in a new text message).
Now what I am trying to do is get the view move up and down with the keyboard. As of right now it starts at the bottom. When keyboard goes up, that view is stuck at the bottom for a second or two and then just appears above the keyboard. Same goes for when the keyboard is dismissed.
I wish I could provide pictures but I guess my reputation is not quite cutting it
Is there a way I can match the transitions or animations of the two so they move together as if they are attached?
The view is initialized
//Create the keyboard UIView
self.keyboardView = [[UIView alloc] initWithFrame:CGRectMake(0, self.view.frame.origin.y + self.view.frame.size.height - (self.navigationController.tabBarController.tabBar.frame.size.height), self.view.frame.size.width, 50)];
Selector used to move the view
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardFrameDidChange:) name:UIKeyboardDidChangeFrameNotification object:nil];
Selector implemented
- (void)keyboardFrameDidChange:(NSNotification*)notification{
NSDictionary* info = [notification userInfo];
CGRect kKeyBoardFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
[self.keyboardView setFrame:CGRectMake(0, kKeyBoardFrame.origin.y - self.keyboardView.frame.size.height, 320, self.keyboardView.frame.size.height)];
self.myScrollView.contentSize = CGSizeMake(self.view.frame.size.width, self.myTableView.frame.size.height);
}
You can do this here is the keyboard notification
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWasShown:)
name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification object:nil];
keyboardWasShown
- (void)keyboardWasShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
double duration = [[[aNotification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
int curve = [[[aNotification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue];
[UIView beginAnimations:#"foo" context:nil];
[UIView setAnimationDuration:duration];
[UIView setAnimationCurve:curve];
CGRect rect=self.viewChatWindow.frame;
rect.size.height=self.viewChatWindow.frame.size.height-kbSize.height;
self.viewChatWindow.frame=rect;
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(scrollToLast)];
[UIView commitAnimations];
}
keyboardWillBeHidden
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
double duration = [[[aNotification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
int curve = [[[aNotification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue];
[UIView beginAnimations:#"foo" context:nil];
[UIView setAnimationDuration:duration];
[UIView setAnimationCurve:curve];
CGRect rect=self.viewChatWindow.frame;
rect.size.height=self.view.frame.size.height-rect.origin.y;
self.viewChatWindow.frame=rect;
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(scrollToLast)];
[UIView commitAnimations];
}
Just wrap your [keyboardView setFrame:...] in an animation block. You can get the keyboard's animation duration and curve from the notification object:
NSTimeInterval duration = [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
UIViewAnimationCurve curve = [notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];
[UIView animateWithDuration:duration delay:0 options:curve animations:^{
self.keyboardView.frame = ...;
} completion:nil];
Using UITextFieldDelegate
This will be your flag that the keyboard is gonna show up
-(void)textFieldDidBeginEditing:(UITextField *)textField{
//Animate like slide up.
[UIView animateWithDuration:0.3
animations:^{
//Use offset rather than contentSize
scrollView.contentOffset = CGPointMake(x,y);
}];
}
When your keyboard is dismissed (resignFirstResponder)
-(void)dismissKeyboard{
[self.view endEditing:YES];
[UIView animateWithDuration:0.3
animations:^{
scrollView.contentOffset = CGPointMake(0,0);
}];
}
Related
I have an application on iPhone who has much content in viewcontroller. Generally the main content is form. My problem is that I put up keyboard and want to type some value to form fields much of content is invisible. I want to scroll this content when keyboard appear. How can I do this?
My view does'n have scroll view however I tried do this but it don't works.
All hints I found so far concern how to put up used textbox, but this is not my assumption.
This is what i did, I changed the top constraint when keyboard rises up and down like this-
in viewDidLoad call this method-
[self observeKeyboard];
#pragma mark- Keyboard Listen Methods
- (void)observeKeyboard {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillChangeFrameNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)keyboardWillShow:(NSNotification *)notification {
NSDictionary *info = [notification userInfo];
NSValue *kbFrame = [info objectForKey:UIKeyboardFrameEndUserInfoKey];
NSTimeInterval animationDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGRect keyboardFrame = [kbFrame CGRectValue];
CGFloat height = keyboardFrame.size.height;
self.COnstraintTopViewVertical.constant=(value of constant)-height;
[UIView animateWithDuration:animationDuration animations:^{
[self.view layoutIfNeeded];
}];
}
- (void)keyboardWillHide:(NSNotification *)notification {
NSDictionary *info = [notification userInfo];
NSTimeInterval animationDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
self.ConstraintTopViewVertical.constant=reset value;
[UIView animateWithDuration:animationDuration animations:^{
[self.view layoutIfNeeded];
}];
}
You can programmatically change position in the view upon keyboard appearance with the following code:
func keyboardWasShown(notification: NSNotification) {
UIView.animateWithDuration(0.3, animations: { () -> Void in
self.setContentOffset(CGPoint(x: setXOffsetHere, y: setYOffsetHere), animated: true)
})
}
This code will transition the view to the coordinates you specify in .setContentOffset call after keyboard appearance. You still have to get the coordinates, but usually they are pretty straightforward to get from storyboard.
Put all your views in a scroll view
Set an auto layout constraint from the bottom of the scroll view to the bottom of the superview
In viewWillAppear
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillChangeFrame:)
name:UIKeyboardWillChangeFrameNotification object:nil];
Handle the KB notification
- (void)keyboardWillChangeFrame:(NSNotification*)aNotification
{
CGRect kbFrame = [aNotification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect kbWindowIntersectionFrame = CGRectIntersection(self.view.window.bounds, kbFrame);
[UIView animateWithDuration:[aNotification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue] animations:^{
self.scrollVBottomConstraint.constant = kbWindowIntersectionFrame.size.height;
[self.view layoutIfNeeded];
}];
}
what i got from your question is: you are using textfield on UIView which is not on the scrollview, now you have to scroll the UIView when keyboard appears. just do following stuff.
-Give the tag to your textfield.
-suppose tag you have given is 4545646
-do not forgot to assign delegate to your textfield (it will execute below delegate method when you start to edit)
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
if (textField.tag == 4545646) {
UIView *contanerView = [self.view viewWithTag:5556466];
[UIView animateWithDuration:0.5 animations:^{
contanerView.frame = CGRectMake(self.view.frame.origin.x+1, -85, self.view.frame.size.width, self.view.frame.size.height-9);
}];
}
}
Change the frame as per your requirement.
and
- (void)textFieldDidEndEditing:(UITextField *)textField {
if (textField.tag == 4545646) {
[textField resignFirstResponder];
UIView *contanerView = [self.view viewWithTag:5556466];
[UIView animateWithDuration:0.5 animations:^{
contanerView.frame = CGRectMake(self.view.frame.origin.x+1, self.view.frame.origin.y, self.view.frame.size.width, self.view.frame.size.height);
}];
}
In viewDidAppear add the following notifications
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyBoardShown:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyBoardDismiss:) name:UIKeyboardWillHideNotification object:nil];
and in keyBoardShown method get the keyboard height
- (void)keyBoardShown:(NSNotification*)notification
{
if(self.view.frame.origin.y>=0)
{
NSDictionary* keyboardInfo = [notification userInfo];
NSValue* keyboardFrameBegin = [keyboardInfo valueForKey:UIKeyboardFrameBeginUserInfoKey];
CGRect keyboardFrameBeginRect = [keyboardFrameBegin CGRectValue];
// NSLog(#"hihi : %f",keyboardFrameBeginRect.size.height);
keyBoardHeight = keyboardFrameBeginRect.size.height-yDeault+50;
if (keyBoardHeight>0) {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
self.view.frame = CGRectMake(self.view.frame.origin.x, (self.view.frame.origin.y-keyBoardHeight), self.view.frame.size.width, self.view.frame.size.height);
[UIView commitAnimations];
}
}
}
in keyBoardDismiss setback the mainview y coordinate to previous value
-(void)keyBoardDismiss:(NSNotification*)notification{
if(self.view.frame.origin.y<0){
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
self.view.frame = CGRectMake(self.view.frame.origin.x, (self.view.frame.origin.y+keyBoardHeight), self.view.frame.size.width, self.view.frame.size.height);
[UIView commitAnimations];
}
}
here yDeault is textfield y coordinate value
yDeault= screenHeight-textField.frame.origin.y+textField.frame.size.height;
Once the keyboard is shown main view will be moved up and once keyboard is dismissed main view will be moved back to the original position
OK. I done this. I need to just add scroll view but in my app probably I have to reconstruct all my view.
No need to add scrollview. Directly you can do this. You can change the self.view.frame without the need of scrollview.
I'm working on a little project. It is basically just a text field where you can type in some short text (basically only a few words) and then you have 3 main buttons below (it looks like a tab bar) you have the option to press keyboard to change the text or type in one if you don't have, you can press colors to choose from different colors for your text or you can press the third button where you can change the font.
So, I just started and I have this issue that if I press the keyboard button the keyboard should appear and the textview should automatically move up for 216px (the height of the keyboard) I have the code below:
The 111 in frame.origin are the y-coordiantes where it should move.
- (IBAction)keyBoardAction:(id)sender {
CGRect frame = _textField.frame;
frame.origin.y = 111;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.0];
_textField.frame = frame;
[UIView commitAnimations];
[_textField becomeFirstResponder];
}
Because it didn't work I run the app without making the textField the firstResponder so that the keyboard would not block my view and I could watch the textField through the whole process.
When I then run the app and pressed the keyboard button, the textField first went down below the screen and then moved upwards again to the same position it was at the beginning.
- (void)registerNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification
object:nil];
}
- (void) keyboardWillShow:(NSNotification *)notification
{
NSDictionary *userInfo = [notification userInfo];
NSTimeInterval duration = userInfo ? [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue] : 1.0;
CGRect keyboardEndFrame;
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];
CGRect newFrame = _textField.frame;
newFrame.origin.y -= keyboardEndFrame.size.height;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration: duration];
_textField.frame = newFrame;
[UIView commitAnimations];
}
I'm implementing real time chat in my app using firebase and and if the keyboard is shown and the user sends me 10 messages in a row, his messages will eventually start hiding behind my keyboard or go out below the tableview view (if the keyboard isn't shown). I believe this has to do with adjusting the view to adjust to the number of rows within the tableview. Ultimately, I need the latest cell to be right above the textfield (whether the keyboard is shown or not) every time I send a message or receive the latest message. Any tips? I took a look at firechat on github and they don't seem to have any code for this: https://github.com/firebase/firechat-ios/blob/master/Firechat/ViewController.m
- (void)viewWillAppear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter]
addObserver:self selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter]
addObserver:self selector:#selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification object:nil];
}
- (void)keyboardWillShow:(NSNotification*)notification
{
[self moveView:[notification userInfo] up:YES];
}
- (void)keyboardWillHide:(NSNotification*)notification
{
[self moveView:[notification userInfo] up:NO];
}
- (void)moveView:(NSDictionary*)userInfo up:(BOOL)up
{
CGRect keyboardEndFrame;
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey]
getValue:&keyboardEndFrame];
UIViewAnimationCurve animationCurve;
[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey]
getValue:&animationCurve];
NSTimeInterval animationDuration;
[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey]
getValue:&animationDuration];
// Get the correct keyboard size to we slide the right amount.
[UIView beginAnimations:nil context:nil];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];
CGRect keyboardFrame = [self.view convertRect:keyboardEndFrame toView:nil];
int y = keyboardFrame.size.height * (up ? -1 : 1);
self.view.frame = CGRectOffset(self.view.frame, 0, y);
[UIView commitAnimations];
}
I am making a chat that functions similar to the one below:
When a user clicks the message bubble, I need it to raise both the UITextField AND the UITableView (with the table view above the text-box of course). And similarly, when they send or retract the message, it should go back down to what it was.
I tried the solution posted here
Two notifications:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHideOrShow:) name:UIKeyboardWillHideNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHideOrShow:) name:UIKeyboardWillShowNotification object:nil];
And the actual function:
- (void)keyboardWillHideOrShow:(NSNotification *)note
{
NSDictionary *userInfo = note.userInfo;
NSTimeInterval duration = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
UIViewAnimationCurve curve = [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue];
CGRect keyboardFrame = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect keyboardFrameForTextField = [self.myTextField.superview convertRect:keyboardFrame fromView:nil];
CGRect newTextFieldFrame = self.myTextField.frame;
newTextFieldFrame.origin.y = keyboardFrameForTextField.origin.y - newTextFieldFrame.size.height;
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState | curve animations:^{
self.myTextField.frame = newTextFieldFrame;
} completion:nil];
}
But it has two problems:
I'm not sure how to raise the tableview on top of the keyboard
When the keyboard goes back down, the input box disappears entirely.
This might help....Cant take credit for it but for the life of me I cant remember where it came from...helped me with a project at one point though so this is how I used it.
This will move the view up and down when the keyboard is called/dismissed based on a BOOL value YES or NO. This way also allows you to have a bit more control over other aspects of it.
- (void) animateTextField: (UITextField*) textField up: (BOOL)up
{
const int movementDistance = 100;
const float movementDuration = 0.3f;
int movement = (up ? -movementDistance : movementDistance);
[UIView beginAnimations: #"anim" context: nil];
[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration: movementDuration];
self.view.frame = CGRectOffset(self.view.frame, 0, movement);
[UIView commitAnimations];
}
And then to implement it:
-(IBAction)goingup:(id)sender
{
//Bounces the text field up for editing
[self animateTextField: yourtextfield up: YES];}
}
-(IBAction)backdown:(id)sender
{
//Bounces it back when keyboard is dismissed
[self animateTextField: yourtextfield up: NO];
}
Connect the actions to your text fields Editing did begin and Editing did end outlets and you're set.
Hope that helps.
I encounter the a problem:
I have a view controller like this.
TO make tool bar up when the keyboard appear, I move the self.view to up.
[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)];
Now I want to click the left button in the tool bar, and appear the view that frame is same as the this keyboard.
But where can I add this view?
if add the subview to the self.view, it will move up with the self.view on the top of the keyboard, not cover.
I'm a beginner about IOS, I have no idea about it, and have searched, but got nothing about this.
another question, IF when the toolbar at the bottom, I aslo want to click the left button on it to show the view(the animation and frame both are the same as the keyboard), how can I do ?
Can you help me?
Thanks
Am I right, that you want to pop the bar above the keyboard attached up and down with the keyboard?
Then you have to register to keyboard show and hide notifications and animate the view up and down based on the notifications and the keyboard show and hide speed.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification object:nil];
Now you have to implement all the selector methods:
//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];
// 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];
[self showSendButton];
}
-(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];
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0, 0, containerView.frame.size.height-46.0f+20.0f, 0);
_table.contentInset = contentInsets;
_table.scrollIndicatorInsets = contentInsets;
//display button based on facebook login status
if ([facebookService.facebook isSessionValid]) {
[commentButton makeButtonLogoutButton];
textView.editable = YES;
} else {
[commentButton makeButtonLoginButton];
textView.editable = NO;
}
}
- (void)keyboardWasShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height+20.0f, 0.0);
_table.contentInset = contentInsets;
_table.scrollIndicatorInsets = contentInsets;
}
Surly replace the given view on top of the keyboard with your own view. This view should be a single view containing all the buttons and stuff.
Greetings
First of all, why do you want to cover the keyboard? It looks like not the very good idea to do so. And I don't think it's even possible at all.
For the answer to your second question you should look at UIView documentation:
[UIView animateWithDuration:0.3 animations:^{
// place your view wherever you want
CGRect frame = myView.frame;
frame.y = self.view.frame.size.height - frame.size.height;
myView.frame = frame;
}];