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.
Related
When the [sendTextField becomeFirstResponder], the keyboard will upspring, and self.view will upspring too.
I have a requirement , when [sendTextField becomeFirstResponder], the keyboard upspring, but self.view do not upspring?
EDIT:For more clear for my question, I add a picture:
My requirement is:
The tableview do not upspring and the textview's back upspring with keyboard popup.
EDIT:For Ajay Gabani's answer, I test in my ipnone-5s using TPKeyboardAvoiding's example , and I found this, the tableView also upspring with the keyboard, the picture will show:
The origin status:
The tableview upspring:
Sorry I am not able to comment on your question.
For your case "when [sendTextField becomeFirstResponder], the keyboard upspring, but self.view do not upspring?"
You can manage textfield within scrollview or tableview with keyboard appearance.
TPKeyboardAvoiding
Hope this might help you.
If you don't want to use 3rd party SDK
you can use observer and manage UIView frame programatically like this
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillBeHidden:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)keyboardWillShow:(NSNotification*)aNotification {
[UIView animateWithDuration:0.25 animations:^
{
CGRect newFrame = [customView frame];
newFrame.origin.y -= [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height; // Adjust your tableview position by taking keyboard height
[tableView setFrame:newFrame];
}completion:^(BOOL finished)
{
}];
}
- (void)keyboardWillBeHidden:(NSNotification*)aNotification {
[UIView animateWithDuration:0.25 animations:^
{
CGRect newFrame = [customView frame];
newFrame.origin.y += [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height; // // Adjust your tableview position
[tableView setFrame:newFrame];
}completion:^(BOOL finished)
{
}];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self.view endEditing:YES];
}
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 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.
This question already has answers here:
How can I make a UITextField move up when the keyboard is present - on starting to edit?
(98 answers)
Closed 9 years ago.
i have a UI textfield in a subview.I am adding it to a view .When the keyboard pops-up ,i want to animate the view to which i am adding this subview.I have written all my textfield delegate functions in my subview class only.So if i use Animate textfield function it doesn't move the parent view instead thy subview is animated....please help me
Try this:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
in the viewDidLoad
and then this
- (void)keyboardWillHide:(NSNotification *)aNotification
{
// the keyboard is hiding reset the table's height
NSTimeInterval animationDuration =
[[[aNotification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGRect frame = self.view.frame;
frame.origin.y += 160;
[UIView beginAnimations:#"ResizeForKeyboard" context:nil];
[UIView setAnimationDuration:animationDuration];
self.view.frame = frame;
[UIView commitAnimations];
}
- (void)keyboardWillShow:(NSNotification *)aNotification
{
// the keyboard is showing so resize the table's height
NSTimeInterval animationDuration =
[[[aNotification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGRect frame = self.view.frame;
frame.origin.y -= 160;
[UIView beginAnimations:#"ResizeForKeyboard" context:nil];
[UIView setAnimationDuration:animationDuration];
self.view.frame = frame;
[UIView commitAnimations];
}
in your view controller
Most likely you will have to change the value (160) that I put here based on your specific view
have you tried textFieldDidBeginEditing i don know whether you tried this or not and whether it is proper way or not. I used this it is working less lines to achieve
-(void)textFieldDidBeginEditing:(UITextField *)textField
{
self.view.frame=CGRectMake(0, -300, 320, 700);
}
this will move your root view to top so your sub view automatically will move to top text field will not be hide behind keyboard and sorry i don have reputation to comment
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.