I had created a Viewcontroller in XCode, everything is working fine. When a phone call comes, the in Call Status bar is pushing the button in the bottom of the view "DOWN" due to that I am unable to click the button during the phone call.
I would like to know how to keep the buttons in the bottom, the same position even when the phone call comes. I tried several methods nothing worked for me.
- (void)statusBarFrameWillChange:(NSNotification*)notification {
NSValue* rectValue = [[notification userInfo] valueForKey:UIApplicationStatusBarFrameUserInfoKey];
CGRect newFrame;
[rectValue getValue:&newFrame];
CGRect fixedFrame = bottomBar.frame;
fixedFrame.origin.y = fixedFrame.origin.y - newFrame.size.height; //Keep the Y position as it is
bottomBar.frame = fixedFrame;
NSLog(#"statusBarFrameWillChange: newSize %f, %f, %f", fixedFrame.origin.y, newFrame.size.width, newFrame.size.height);
}
- (void)statusBarFrameChanged:(NSNotification*)notification {
NSValue* rectValue = [[notification userInfo] valueForKey:UIApplicationStatusBarFrameUserInfoKey];
CGRect oldFrame;
[rectValue getValue:&oldFrame];
CGRect fixedFrame = bottomBar.frame;
fixedFrame.origin.y = fixedFrame.origin.y + oldFrame.size.height;
bottomBar.frame = fixedFrame;
NSLog(#"statusBarFrameChanged: oldSize %f, %f, %f", fixedFrame.origin.y, oldFrame.size.width, oldFrame.size.height);
}
Using autolayout, make sure you set a Bottom Space constraint:
Related
So I'm not sure why my code isn't working. When the keyboard appears it puts the toolBar above the keyboard, but much higher than the height of the keyboard. Also the quick text bar in ios8 messes it up even more when I toggle it on and off, and the toolBar doesn't adjust correctly. Also when I close out the keyboard the first time the toolBar goes back to its original position, but then after once it doesn't go back down all the way where it was originally. I logged out self.yPositionStore and it never changes, which is why I don't understand why it doesn't always go back to the same spot. I've literally been working on this code all day trying to find a solution to my textfield getting hidden by the keyboard and it's giving me a headache. someone PLEASE help me.
- (void)viewDidLoad {
[super viewDidLoad];
self.yPositionStore = self.toolBar.frame.origin.y;
}
- (void)keyboardWasShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
CGRect newFrame = self.toolBar.frame;
newFrame.origin.y = kbSize.height;
self.toolBar.frame = newFrame;
}
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
CGRect newFrame = self.toolBar.frame;
newFrame.origin.y = self.yPositionStore;
self.toolBar.frame = newFrame;
}
There was problem in keyboardwasshown method. you have to subtract toolbar height and keyboard height from main screen height to find exact y value for toolbar.
- (void)viewDidLoad {
[super viewDidLoad];
self.yPositionStore = self.toolBar.frame.origin.y;
}
- (void)keyboardWasShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
CGRect newFrame = self.toolBar.frame;
newFrame.origin.y = [UIScreen mainscreen].bounds.size.height - kbSize.height - newFrame.size.height;
self.toolBar.frame = newFrame;
}
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
CGRect newFrame = self.toolBar.frame;
newFrame.origin.y = self.yPositionStore;
self.toolBar.frame = newFrame;
}
ok so for the most part this winded up working
- (void)keyboardWasShown:(NSNotification*)aNotification
{
self.yPositionStore = self.toolBar.frame.origin.y;
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
CGRect newFrame = self.toolBar.frame;
newFrame.origin.y = [UIScreen mainScreen].bounds.size.height - kbSize.height - newFrame.size.height;
self.toolBar.frame = newFrame;
}
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
CGRect newFrame = self.toolBar.frame;
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
newFrame.origin.y += kbSize.height - newFrame.size.height;
self.toolBar.frame = newFrame;
}
After the first time the keyboard is hidden, the tool bar goes down about a pixel further than it's suppose to, but it still looks good. The other problem I'm still having is on keyboardWasShown, the toolbar is repositioning itself but it's a little bit delayed, and I'm not sure how to fix that. Now off to trying out how to reposition a tableview with the keyboard!
I am using a UIKeyboardWillShowNotification to know when the keyboard is shown and adjust the size of my UIWebView so that it isn't hidden behind the keyboard.
The strange thing is, when I change the frame in the method that gets called by NSNotificationCenter it changes the frame in a way that lets me scroll my UIWebView content (red in screenshot), but also a large portion of the UIWebView scrolls into view (yellow in screenshot). The yellow should never be shown.
- (void)keyboardWillShowOrHide:(NSNotification *)notification {
// User Info
NSDictionary *info = notification.userInfo;
CGFloat duration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue];
int curve = [[info objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue];
CGRect keyboard = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
if ([notification.name isEqualToString:UIKeyboardWillShowNotification]) {
[UIView animateWithDuration:duration delay:0 options:curve animations:^{
CGRect frame = self.toolbarHolder.frame;
frame.origin.y = (self.view.frame.size.height - keyboard.size.height) - 44;
self.toolbarHolder.frame = frame;
// Editor View
CGRect editorFrame = self.editorView.frame;
editorFrame.size.height = (self.view.frame.size.height - keyboard.size.height) - 44;
self.editorView.frame = editorFrame;
} completion:nil];
} else {
[UIView animateWithDuration:duration delay:0 options:curve animations:^{
CGRect frame = self.toolbarHolder.frame;
frame.origin.y = self.view.frame.size.height;
self.toolbarHolder.frame = frame;
// Editor View
CGRect editorFrame = self.editorView.frame;
editorFrame.size.height = self.view.frame.size.height;
self.editorView.frame = editorFrame;
} completion:nil];
}
}
If I change the UIWebView frame in a different method than the one called from NSNotificationCenter, the frame changes correctly and the area above the keyboard is only filled with my HTML content within the UIWebView (red).
What could be causing this issue?
Use UIKeyboardFrameEndUserInfoKey key that returns the final expected frame for keyboard
I am trying to resize the UITextView when the keyboard is open.
in order to give my UITextView a new size ( so that it doesn't become shadowed by the keyboard) I make the following calculation
firstResult = UITextView bottom coordinate - keyboard top coordinate
firstResult should now have the size of the shadowed UITextView frame
then i do textView.frame.size.height -= firstResult which now should have a new size that would not be shadowed by the keyboard.
The problem with the code as it stands out is that there is always part of the UIView that is hidden behind the keyboard.
Could anyone point out what's wrong with my calculations so that the new size is always right? or any other way that I could use to resize the UITextView appropriately because all examples I find online do not work somehow.
the code
- (void)keyboardWasShown:(NSNotification *)notification {
CGRect viewFrame = input.frame;
CGFloat textEndCord = CGRectGetMaxY(input.frame);
CGFloat kbStartCord = input.frame.size.height - ([[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue]).size.height;
CGFloat result = fabsf( input.frame.size.height - fabsf( textEndCord - kbStartCord ));
viewFrame.size.height -= result;
NSLog(#"Original Height:%f, TextView End Cord: %f, KB Start Cord: %f, resutl: %f, the sum: %f",input.frame.size.height, textEndCord,kbStartCord,result,fabsf( textEndCord - kbStartCord ));
input.frame = viewFrame;
}
There is a problem on the calculation, try this instead,
- (void)keyboardWasShown:(NSNotification *)notification {
CGRect viewFrame = input.frame;
CGFloat textEndCord = CGRectGetMaxY(input.frame);
CGFloat kbStartCord = textEndCord - ([[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue]).size.height;
viewFrame.size.height = kbStartCord;
input.frame = viewFrame;
}
Edited
General formula also for also supporting Landscape mode
- (void)keyboardWasShown:(NSNotification *)notification {
CGFloat keyboardHeight;
CGRect viewFrame = textView.frame;
CGFloat textMaxY = CGRectGetMaxY(textView.frame);
if (UIInterfaceOrientationIsLandscape(self.interfaceOrientation)) {
keyboardHeight = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size.width;
} else {
keyboardHeight = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size.height;
}
CGFloat maxVisibleY = self.view.bounds.size.height - keyboardHeight;
viewFrame.size.height = viewFrame.size.height - (textMaxY - maxVisibleY);
textView.frame = viewFrame;
}
I had to add the UIInterfaceOrientationIsLandscape conditional since [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size.height; doesn't work when device is on Landscape. I know it's a little tricky, the other way of going around this would be detecting device rotation and changing a parameter's value. It is up to you.
Formula explanation
objective-c
On iPhone, I found when keyboard shows up, the system will set contentInset of tableView to UIEdgeInsets(0, 0, 216, 0) , because the keyboard height is 216. I think this is convienent when design an app only for the newest iOS, in the past, I have to calculate tableView size when keyboard came up by myself.
But I have to support iOS5, so I wanna know how to disable this automatic "favor" for me ? If I set
self.searchTipsController.tableView.contentInset = UIEdgeInsetsZero; , the scroll indicator will not show. At last I have to detect system version to do handle it separately.
And I want to know from what version this feature begins? 6.0 or 6.1?
- (void) keyboardSizeChange:(NSNotification *)aNotification
{
NSDictionary* d = [aNotification userInfo];
CGRect r = [[d objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
if(r.origin.y<[UIScreen mainScreen].bounds.size.height)
{
CGRect convertRect = [self.view convertRect:r fromView:[UIApplication sharedApplication].keyWindow];
CGRect viewBounds = self.view.bounds;
CGRect tipsFrame = CGRectMake(0, 0, viewBounds.size.width, convertRect.origin.y);
if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"6.1"))
{
}else
{
self.searchTipsController.view.frame = tipsFrame;
self.searchTipsController.tableView.contentInset = UIEdgeInsetsZero;
}
}
}
I change my code, when keyboard raises, remove the tableview then add it back, this time it looks right..
- (void) keyboardSizeChange:(NSNotification *)aNotification
{
NSDictionary* d = [aNotification userInfo];
CGRect r = [[d objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
if(r.origin.y<[UIScreen mainScreen].bounds.size.height)
{
CGRect convertRect = [self.view convertRect:r fromView:[UIApplication sharedApplication].keyWindow];
CGRect viewBounds = self.view.bounds;
CGRect tipsFrame = CGRectMake(0, 0, viewBounds.size.width, convertRect.origin.y);
self.searchTipsController.view.frame = tipsFrame;
self.searchTipsController.tableView.contentInset = UIEdgeInsetsZero;
[self.searchTipsController.view removeFromSuperview];
[self.view addSubview:self.searchTipsController.view];
}
}
But I still hope some one can answer my question, thanks.
I have a UIScrollView, which contains UITextFields and UITextViews. I have registered for the UIKeyboardDidChangeFrameNotification. When I tap on a text field or text view, the did change frame notification action is triggered and I adjust the contentOffset of the scroll view as shown below
- (void)keyboardDidChangeFrame:(NSNotification *)notification
{
CGRect keyboardEndFrame;
[[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGRect intersection;
UIView *theFirstResponder = [[UIApplication sharedApplication].keyWindow findFirstResponder];
if ([theFirstResponder isKindOfClass:[UITextView class]]) {
if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft) {
keyboardEndFrame = CGRectMake(keyboardEndFrame.origin.y, 416, keyboardEndFrame.size.height, keyboardEndFrame.size.width);
}
else if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeRight)
{
keyboardEndFrame = CGRectMake(keyboardEndFrame.origin.y, 0, keyboardEndFrame.size.height, keyboardEndFrame.size.width);
}
}
else
keyboardEndFrame = CGRectMake(keyboardEndFrame.origin.y, keyboardEndFrame.origin.x, keyboardEndFrame.size.height, keyboardEndFrame.size.width);
screenRect = CGRectMake(screenRect.origin.y, screenRect.origin.x, screenRect.size.height, screenRect.size.width);
if(CGRectEqualToRect(lastKBDRect, keyboardEndFrame)) {
return;
}
lastKBDRect = keyboardEndFrame;
if (CGRectIntersectsRect(keyboardEndFrame, screenRect)) {
// Keyboard is visible
//Convert Frame of the first responder, in context of the view that needs to be shifted
UIView *firstResponder = [[UIApplication sharedApplication].keyWindow findFirstResponder];
CGRect theRect = [firstResponder convertRect:firstResponder.frame toView:[UIApplication sharedApplication].keyWindow];
theRect = CGRectMake(theRect.origin.y, theRect.origin.x > 768 ? 750 : theRect.origin.x, theRect.size.height, theRect.size.width);
intersection = CGRectIntersection(keyboardEndFrame, theRect);
//If intersection is null, then no need to shift anything. Simply return.
if(CGRectIsNull(intersection)) {
return;
}
//Shift the view so that the first responder view is completely visible, keeping the constraint that the origin of the first responder view is also visible.
//Remember the current offset, so when we shift the view back, we shift it to the proper position.
if (!wasContentViewShifted) {
lastContentOffset = contentScrollView.contentOffset;
lastContentSize = contentScrollView.contentSize;
wasContentViewShifted = YES;
}
CGFloat offset = theRect.origin.y + theRect.size.height - keyboardEndFrame.origin.y;
if((theRect.origin.y - offset) < 40) {
offset += 42;
}
[UIView animateWithDuration:0.3f animations:^{
contentScrollView.contentOffset = CGPointMake(0, contentScrollView.contentOffset.y + offset);
contentScrollView.contentSize = CGSizeMake(0, lastContentSize.height + (600 - theRect.size.height));
}];
} else {
// Keyboard is hidden. Move the view back only if it was shifted.
if(wasContentViewShifted) {
wasContentViewShifted = NO;
[UIView animateWithDuration:0.3f animations:^{
contentScrollView.contentOffset = lastContentOffset;
contentScrollView.contentSize = lastContentSize;
}];
}
}
}
The application supports only landscape orientation.
The problems I'm facing here are
Tapping on textView presents the keyboard and textview is scrolled to the top if it is hidden by keyboard. Now, changing the orientation (landscape left to landscape Right) makes the textView scroll further to top and hence invisible.
The scrolling of TextView sometimes works for landscape left orientation but not for landscape right orientation and vice versa. This is because of the keyboardEndFrame values I'm using. Shouldn't I use the keyboardEndFrame origin values ? If not, what would be the alternative ?
Sometimes the it works for the textField but not for the textView.
Instead of having such complex solution you can try using this.
One simpler solution can also be found here.
Also it is not advisable to hard code the frames as you are doing. Refer to the apple documentation for more details.