I have added code for pushing table view above keyboard. I have change the bottomLayout constraint of table view. But, he i set the constraint, there is an extra space above keyboard.
I have added sample code for keyboard showing notification.
- (void)keyboardWillShow:(NSNotification*)notification
{
CGRect rect = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect rectInView = [self.view rect fromView:nil];
[UIView animateWithDuration:0.25 animations:^{
self.bottomLayoutConstraint.constant = rectInView.size.height;
[self.view layoutIfNeeded];
}];
}
After this i got the following output in the keyboard.
Related
I have UITableView with UITextfields as the subview in contentView.
They work and all, but when I select the bottom ones, they are getting covered by the keyboard, so I want the UITableView to scroll up.
Here is my current code:
-(void)keyboardWillShow:(NSNotification*)notification {
NSValue *keyboardFrameValue = [[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey];
CGRect keyboardFrame = [[self view] convertRect:[keyboardFrameValue CGRectValue] fromView:nil];
[UIView animateWithDuration:0.3 animations:^{
[constraint setConstant:keyboardFrame.size.height];
[self.myTableView layoutIfNeeded];
}];
}
-(void)keyboardWillHide:(NSNotification *)notification {
[UIView animateWithDuration:0.3 animations:^{
[constraint setConstant:0];
[self.myTableView layoutIfNeeded];
}];
}
The problem with this is that it messes up the data, textfields are being added to the wrong Cells and stuff.
Hope that anyone can help out.
If possible, use an UITableViewController, the keyboard is handled automatically.
Otherwise, adjust the contentInset property of the table view as outlined by Apple.
I have a UIView with a UITextField placed at the bottom of the screen which I'd like to move up when a keyboard appears.
I have added keyboardFrameDidChange observer for getting notified whenever a keyboard appears/disappears. Here is the method :
-(void)keyboardFrameDidChange:(NSNotification*)notification{
NSDictionary* info = [notification userInfo];
CGRect kKeyBoardFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
[bottomView layoutIfNeeded];
[UIView animateWithDuration:[notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue] delay:0 options:[[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] integerValue] animations:^{
[bottomView setFrame:CGRectMake(0, kKeyBoardFrame.origin.y - bottomView.frame.size.height, 320, bottomView.frame.size.height)];
} completion:^(BOOL finished) {
[bottomView layoutIfNeeded];
NSLog(#"frame ** %f",self.bottomView.frame.origin.y);
}];
}
Here the frame of bottomView is changing but nothing happens in the UI. The bottomView just remains at the bottom. What might be the reason?
This sounds like an auto layout problem. If auto layout is on, then you should change the view's position by adjusting its constraints, not setting frames. Make an IBOutlet to the constraint between the text field and the bottom of superview (bottomCon in my example), and adjust it.
-(void)keyboardFrameDidChange:(NSNotification*)notification{
NSDictionary* info = [notification userInfo];
CGRect kKeyBoardFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
[_bottomView layoutIfNeeded];
[UIView animateWithDuration:[notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue] delay:0 options:[[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] integerValue] animations:^{
self.bottomCon.constant = kKeyBoardFrame.origin.y;
[_bottomView layoutIfNeeded];
} completion:^(BOOL finished) {
NSLog(#"frame ** %f",self.bottomView.frame.origin.y);
}];
}
I have a view for which I'm trying to animate a height change when the keyboard slides up (code shown below). The view on which I'm calling the frame change is animating perfectly; however, That view contains a subview, which in turn contains a textfield (which is causing the keyboard to pop up), and these subviews are just jumping to their new locations instead of animating. I put auto layout constraints on the subview to constrain it to the left, bottom and right of the superview as well as maintain a constant height.
Example video here: http://youtu.be/EmcZ-cXeTbM
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(slideViewForKeyboard:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(slideViewForKeyboard:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)slideViewForKeyboard:(NSNotification *)note {
NSDictionary* userInfo = [note 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];
CGRect newFrame = CGRectMake(self.view.frame.origin.x,
self.view.frame.origin.y,
self.view.frame.size.width,
keyboardEndFrame.origin.y);
[UIView animateWithDuration:0 delay:0 options:(animationCurve << 16) animations:^{
[self.view setFrame:newFrame];
}completion:^(BOOL completed){}];
}
- (IBAction)endEditingOnTap:(UITapGestureRecognizer *)sender {
[self.view endEditing:YES];
}
#end
You should be using animationDuration as the duration of your animation block.
Aside from that, you have another problem. Right now, you set the frame of your view inside the animation block, so the change is animated. But the system lays out the subviews later, during the layout phase of the run loop, outside your animation block. This means the subviews won't be animated to their new frames.
You can fix that by sending layoutIfNeeded to your view inside the animation block:
[UIView animateWithDuration:animationDuration delay:0 options:(animationCurve << 16) animations:^{
self.view.frame = newFrame;
[self.view layoutIfNeeded];
} completion:^(BOOL completed){}];
But you'll probably run into another problem. You're setting the frame of your view directly, but you're using auto layout. At some point, auto layout will probably set the frame back based on your constraints. You need to modify the constraints on your view to control its new frame, instead of setting the frame directly.
Set animation duration.
[UIView animateWithDuration:0.3 delay:0 options:(animationCurve << 16) animations:^{
[self.view setFrame:newFrame];
}completion:^(BOOL completed){}];
You're passing in 0 to -[UIView animateWithDuration:delay:options:animations:completion]. This will not result in an animation because its going from frame 0 to frame n-1 (where n is the number of frames it would have generated) in 0 seconds, aka instantaneously. Try passing your animationDuration as the argument for duration that way it animates at the same speed as the keyboard
I have a TextView. When keyboard appears, part of the TextView is hidden behind keyboard. So, I decrease its height by decreasing its bottom constraint(with its superview's bottom) so that user can scroll and see whole text.
But issue is when keyboard disappears its not resizing TextView's height to original. But when I tap on it, it shows whole text same as in first image.
How it looks normally :
How it looks when keyboard has appeared :
How it looks when keyboard has disappeared :
Now, if I tap on TextView it looks same as first image. i.e. resizes to have proper size :
Code : self.messageView is TextView.
// Called when keyboard is going to be displayed
- (void)keyboardWillShow:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
// get animation info from userInfo
NSTimeInterval animationDuration;
CGRect keyboardFrame;
[[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
[[info objectForKey:UIKeyboardFrameBeginUserInfoKey] getValue:&keyboardFrame];
// Save constant to set back later
self.bottomConstant = self.noticeMessageBottom.constant;
// Change bottom space constraint's constant
self.noticeMessageBottom.constant = keyboardFrame.size.height + 8.0f;
[UIView animateWithDuration:animationDuration delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
[self.messageView setNeedsLayout];
[self.messageView layoutIfNeeded];
[self.view setNeedsLayout];
[self.view layoutIfNeeded];
} completion:nil];
[self.messageView flashScrollIndicators];
}
// Called when keyboard is going to be hidden
- (void)keyboardWillHide:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
// get animation info from userInfo
NSTimeInterval animationDuration;
CGRect keyboardFrame;
[[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
[[info objectForKey:UIKeyboardFrameBeginUserInfoKey] getValue:&keyboardFrame];
// Reset contentOffset
self.messageView.contentOffset = CGPointZero;
// Change bottom space constraint's constant
self.noticeMessageBottom.constant = self.bottomConstant;
[UIView animateWithDuration:animationDuration delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
[self.messageView setNeedsLayout];
[self.messageView layoutIfNeeded];
[self.view setNeedsLayout];
[self.view layoutIfNeeded];
} completion:nil];
}
Update : I set background color to TextView and saw that height is changed properly but part of the text is not visible. It becomes visible when I tap on it.
Note : This happens only if TextView's contentOffset is (0,0).i.e user has not scrolled it. If user has scrolled it and contentOffset is not (0,0) then it works fine.
I just unchecked scroll enabled property of TextView in storyboard and its not giving that issue any more.
I have a table view with static cells. One cell contains a UITextView and the heightForRowAtIndexPath: is calculated dynamically so that the cell is always tall enough to accomodate the text (that part took some work under iOS 7, actually, as it's no longer possible to simply ask the textView for its contentSize).
When I tap within the text view to start editing, the keyboard animates into place, the contentInsets on the tableView are automatically adjusted to account for this (ie, bottom inset of 216px for iPhone portrait orientation), the cursor / caret becomes visible, and then the table view scrolls to another location. It ends up looking like a bounce.
Here's a video of this in the simulator: https://www.dropbox.com/s/htdbb0t7985u6n4/textview-bounce.mov
Notice that for a second the caret is just above the keyboard. I've been logging the table view's contentOffset and I can see it scroll to a nice value and then suddenly "turn around" and scroll back.
Oddly, if I turn on slow animations in the simulator the problem disappears; the contentOffset reversal doesn't happen and things work as I expect (ie, iOS 6 behavior).
Here's the video with slow animations: https://www.dropbox.com/s/nhn7vspx86t4exb/textview-nobounce.mov
Implementation notes:
The text view is pink and has AutoLayout constraints that keep it pinned to the cell at distance 0 (except left side, which is 10pts)
I'm using boundingRectWithSize: to calculate the table view height, adjusting for lineFragmentPadding and any top/bottom insets. Seems to work.
I have set the textView to not be scrollable, but didn't notice anything different when scrollEnabled == YES
This is a table view controller and automaticallyAdjustsScrollViewInsets == YES
Try to adjust UITableView frame when keyboard appears. Call [self attachKeyboardHelper] in viewWillAppear and [self detachKeyboardHelper] in viewWillDisappear.
- (void)attachKeyboardHelper{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillAppear:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
}
- (void)detachKeyboardHelper{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)keyboardWillAppear:(NSNotification *)notification{
NSDictionary* userInfo = [notification 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];
CGRect keyboardFrame = [self.view convertRect:keyboardEndFrame toView:nil];
if(self.view==self.tableView){
CGRect newTableFrame = CGRectMake(self.tableView.frame.origin.x, self.tableView.frame.origin.y, self.tableView.frame.size.width, self.view.bounds.size.height-keyboardFrame.size.height);
self.tableView.frame = newTableFrame;
}else{
CGRect newTableFrame = CGRectMake(self.tableView.frame.origin.x, self.tableView.frame.origin.y, self.tableView.frame.size.width, self.view.bounds.size.height-self.tableView.frame.origin.y-keyboardFrame.size.height);
self.tableView.frame = newTableFrame;
}
[UIView commitAnimations];
}
- (void)keyboardWillHide:(NSNotification *)notification{
NSDictionary* userInfo = [notification userInfo];
NSTimeInterval animationDuration;
UIViewAnimationCurve animationCurve;
CGRect keyboardEndFrame;
[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];
CGRect newTableFrame = CGRectMake(self.tableView.frame.origin.x, self.tableView.frame.origin.y, self.tableView.frame.size.width, self.view.superview.bounds.size.height-self.tableView.frame.origin.y);
self.tableView.frame = newTableFrame;
if(newTableFrame.size.height>self.tableView.contentSize.height-self.tableView.contentOffset.y){
float newOffset=MAX(self.tableView.contentSize.height-newTableFrame.size.height, 0);
[self.tableView setContentOffset:CGPointMake(0, newOffset) animated:YES];
}
}