I'm trying to move the my view up when keyboard appears and then down again on disappear.
The first time the keyboard appears , it works as intended . When I press 'Done' , keyboard disappears and view moves back. However , after this initial editing , clicking on the textfiled does nothing. The keyboard doesn't come up at all.
In viewDidLoad method I've written :
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil];
And implemented the following delegates :
- (void)keyboardDidShow:(NSNotification *)notification
{
//Assign new frame to your view
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
NSDictionary* info = [notification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
[self.view setFrame:CGRectMake(0,-kbSize.height,320,460)];
[UIView commitAnimations];
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField {
[self.view endEditing:YES];
return NO;
}
-(void)keyboardDidHide:(NSNotification *)notification
{ [UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
[self.view setFrame:CGRectMake(0,0,320,460)];
[UIView commitAnimations];
}
I don't recommend you to move self.view for it. Put all subviews on scrollview or tableview and assign this class on it.
https://github.com/michaeltyson/TPKeyboardAvoiding
You need to implement resignFirstResponder on your UITextfield so that the keyboard can be launched again. In your implementation what you could do is add the following line to your textFieldShouldReturn method:
[textfield resignFirstResponder];
If you change your -textFieldShouldReturn method to the following it should work.
-(BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return YES;
}
Per the documentation:
By returning NO, you could prevent the user from switching to another control
Returning NO, keeps focus on the control, so I'm assuming that the next time you tap the textFiled nothing happens because the system thinks that control is already focused.
Related
I have a UITextView (purpose : comment) pinned at the bottom of my screen, when the user wants to add a comment, the keyboard appears and I have the comment view shift upwards along with the comment. I also have a cancel button to hide the keyboard, but the keyboard isn't hidden
//Set up NSNotification for Keyboard
-(void) viewWillAppear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillToggle:)
name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillToggle:)
name:UIKeyboardWillHideNotification object:nil];
}
//Code to shift comment view up with keyboard
- (void) keyboardWillToggle:(NSNotification *)aNotification
{
CGRect frame = [self.navigationController.toolbar frame];
CGRect keyboard = [[aNotification.userInfo valueForKey:#"UIKeyboardFrameEndUserInfoKey"] CGRectValue];
frame.origin.y = keyboard.origin.y - frame.size.height;
[UIView animateWithDuration:[[aNotification.userInfo valueForKey:#"UIKeyboardAnimationDurationUserInfoKey"] floatValue] animations:^
{
[self.navigationController.toolbar setFrame:frame];
}];
}
//Hide keyboard
-(void)cancelComment:(UIBarButtonItem*)sender{
NSLog(#"cancelComment called");
[self.view endEditing:YES];
}
I feel like this should work? "cancelComment called" is being logged to the console but the keyboard isn't hidden
SOLUTION:
You have forgotten to put:
[yourtextfield resignfirstresponder];
in your cancelComment function.
you can try
-(void)cancelComment:(UIBarButtonItem*)sender{
NSLog(#"cancelComment called”);
[self.navigationController.view endEditing:YES];
}
I think you textView not in self.view and in the self.navigationController.view
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[yourtextfieldname resignfirstresponder];
}
Hope this will you!
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 have a UIView which contains another UIView object called contentView. Inside contentView, I have several UITextField objects. So that the current editing UITextField is always visible and not being hidden by the keyboard, I am altering the constraints on the contentView inside the textFieldDidBeginEditing: method. This means the contentView slides up and down inside the parent UIView, and keeps the relevant UITextField visible. This part is working fine, but here is a code fragment:
- (void)textFieldDidBeginEditing:(UITextField *)textField
//offset calculation removed for clarity
NSInteger offset = ....
self.contentViewTopConstraint.constant = -offset;
self.contentViewBottomConstraint.constant = offset;
[self.view setNeedsUpdateConstraints];
[UIView animateWithDuration:0.3 animations:^{
[self.view layoutIfNeeded];
}];
}
I have noticed that if I type some text into the first UITextField, and then tap on the second UITextField, the text in the first UITextField jumps upwards and then back down again. If I disable the animation in the above code fragment, this behaviour goes away. So my guess is that when editing a UITextField, some other constraints are set, which are then altered as focus moves away from that UITextField. As I'm telling the view to update it's constraints in an animated fashion, this causes the text to move around.
Is there some way I can avoid this, but still maintain the animation for moving the contentView up and down?
Edit: Adding an extra [self.view layoutIfNeeded] call before I update any constraints fixed the issue. I'm still not to sure what might have been going on though, or really why this fixed it. Anyone have any insight?
I have since learned that the correct way to animate constraints is like this:
- (void)textFieldDidBeginEditing:(UITextField *)textField
//offset calculation removed for clarity
NSInteger offset = ....
[self.view layoutIfNeeded];
self.contentViewTopConstraint.constant = -offset;
self.contentViewBottomConstraint.constant = offset;
[UIView animateWithDuration:0.3 animations:^{
[self.view layoutIfNeeded];
}];
}
This resolved the issue I was having.
I am not sure what is wrong with your piece of code, more code would be required for me to tell what is wrong in that, But you can use this piece of code, it will work for you
-(void)addObservers
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardIsShowing:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardIsHiding:)
name:UIKeyboardWillHideNotification
object:nil];
}
-(void)removeObservers
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
- (void)keyboardIsShowing:(NSNotification*)notification
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:[notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
[UIView setAnimationCurve:[notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue]];
[UIView setAnimationBeginsFromCurrentState:YES];
int scaleFactor = 0;
if([oldPasswrdField isFirstResponder])
scaleFactor = 20;
else if([newPasswrdField isFirstResponder])
scaleFactor = 76;
else if([confirmPasswrdField isFirstResponder])
scaleFactor = 132;
self.contentView.frame = CGRectMake(self.contentView.frame.origin.x, self.view.frame.origin.y-scaleFactor,self.contentView.frame.size.width, self.contentView.frame.size.height);
[UIView commitAnimations];
}
- (void)keyboardIsHiding:(NSNotification*)notification
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:[notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
[UIView setAnimationCurve:[notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue]];
[UIView setAnimationBeginsFromCurrentState:YES];
self.contentView.frame = CGRectMake(self.contentView.frame.origin.x, 0, self.contentView.frame.size.width, self.contentView.frame.size.height);
//self.view.frame = frame;
[UIView commitAnimations];
}
You see the scalefactor in keyboardIsShowing method. It is needed to be set according to the textfield you are editing. If you can, you can just fetch the current responding text field and take it's origin.y and set the scale factor according to that. Also, call addObservers in viewDidAppear and call removeObservers in viewDidDisappear. Or according to your needs, but don't forget to call them both once.
Edit: Tell me if this works for you or if you need further help on the matter, would be glad to assist.
I have a toolbar which I need to use when editing text, and when not.
In previous apps, I've moved the toolbar manually (listening for notifications, etc.)
But I want to use inputAccessoryView... so in my viewDidLoad, I do
for (/*myTextFields*/) {
textField.inputAccessoryView = keyboardToolbar;
}
[self.view addSubView:keyboardToolbar];
Which works fine, the toolbar appears, I click on a text field, toolbar slides up - all good.
But when I then hide the keyboard, inputAccessoryView drags my toolbar off the screen. Is there any way to tell the inputAcessoryView where it's fixed location is? - Or do I have to go back to my old way of listening for notifications etc...?
I solved this by listening for Notifications and moving the toolbar up... oh well.
Something like this does the job:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
/* Listen for keyboard */
[[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
{
[keyboardToolbar setItems:itemSetFull animated:YES];
/* Move the toolbar to above the keyboard */
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
CGRect frame = self.keyboardToolbar.frame;
frame.origin.y = self.view.frame.size.height - 210.0;
self.keyboardToolbar.frame = frame;
[UIView commitAnimations];
}
- (void)keyboardWillHide:(NSNotification *)notification
{
[keyboardToolbar setItems:itemSetSmall animated:YES];
/* Move the toolbar back to bottom of the screen */
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
CGRect frame = self.keyboardToolbar.frame;
frame.origin.y = self.view.frame.size.height - frame.size.height;
self.keyboardToolbar.frame = frame;
[UIView commitAnimations];
}
I guess input accessory view is literally just meant for something stuck on top of the keyboard :)
I've figured it out recently, and it seems few people have. So, I would like to direct you to this answer: https://stackoverflow.com/a/24855095/299711, which I will just copy below:
Assign your UIToolbar to a property in your view controller:
#property (strong, nonatomic) UIToolbar *inputAccessoryToolbar;
In your top view controller, add these methods:
- (BOOL)canBecomeFirstResponder{
return YES;
}
- (UIView *)inputAccessoryView{
return self.inputAccessoryToolbar;
}
And then (optionally, as it usually shouldn't be necessary), whenever the keyboard gets hidden, just call:
[self becomeFirstResponder];
That way, your inputAccessoryToolbar will be both your view controller's and your text view's input accessory view.