I have an iOS app. It works great.
Except when the user has a hotspot on or is in a call but the call app is minimised
The extended height of the status bar pushes my ui down, making part of it disappear,
at the bottom.
I want this extended bar to overlay the top of the screen and not push the ui downwards.
How do I achieve that ?
The Simplest Solution is to make sure that your view's springs-and-struts or Autolayout properties allow for compression or expansion of the view , If you have some complex UI then you can implement UIApplicationWillChangeStatusBarFrameNotification observer.
You can handle the UIApplicationWillChangeStatusBarFrameNotification and UIApplicationDidChangeStatusBarOrientationNotification notifications which will tell you the new size of the status bar.
If you are intent on using a transform on your view to handle resizing, you can implement -viewWillLayoutSubviews in your view controllers (probably in a common base class) to set a transform on the root view of the view controller.
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(statusFrameChanged:)
name:UIApplicationWillChangeStatusBarFrameNotification
object:nil];
}
-(void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIApplicationWillChangeStatusBarFrameNotification
object:nil];
}
- (void)statusFrameChanged:(NSNotification*)note
{
CGRect statusBarFrame = [note.userInfo[UIApplicationStatusBarFrameUserInfoKey] CGRectValue];
CGFloat statusHeight = statusBarFrame.size.height;
UIScreen *screen = [UIScreen mainScreen];
CGRect viewRect = screen.bounds;
viewRect.size.height -= statusHeight;
viewRect.origin.y = statusHeight;
self.view.frame = viewRect;
[self.view setNeedsLayout];
}
- (void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
CGRect baseFrame = self.view.frame;
// 548.0 is the full height of the view. Update as necessary.
CGFloat scale = self.view.frame.size.height / 548.0;
[self.view setTransform:CGAffineTransformMakeScale(1.0, scale)];
self.view.frame = baseFrame;
}
I used use "Vertical space - Bottom layout Guide - Button". This way, a button I have on the bottom of the screen stays in the same place when there is an in call bar and if a different screen size is used (3.5inch or 4icnh).
Related
I have an iOS app. It works great.
Except when the user has a hotspot on or is in a call but the call app is minimised
The extended height of the status bar pushes my ui down, making part of it disappear,
at the bottom.
I want this extended bar to overlay the top of the screen and not push the ui downwards.
How do I achieve that ?
The Simplest Solution is to make sure that your view's springs-and-struts or Autolayout properties allow for compression or expansion of the view , If you have some complex UI then you can implement UIApplicationWillChangeStatusBarFrameNotification observer.
You can handle the UIApplicationWillChangeStatusBarFrameNotification and UIApplicationDidChangeStatusBarOrientationNotification notifications which will tell you the new size of the status bar.
If you are intent on using a transform on your view to handle resizing, you can implement -viewWillLayoutSubviews in your view controllers (probably in a common base class) to set a transform on the root view of the view controller.
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(statusFrameChanged:)
name:UIApplicationWillChangeStatusBarFrameNotification
object:nil];
}
-(void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIApplicationWillChangeStatusBarFrameNotification
object:nil];
}
- (void)statusFrameChanged:(NSNotification*)note
{
CGRect statusBarFrame = [note.userInfo[UIApplicationStatusBarFrameUserInfoKey] CGRectValue];
CGFloat statusHeight = statusBarFrame.size.height;
UIScreen *screen = [UIScreen mainScreen];
CGRect viewRect = screen.bounds;
viewRect.size.height -= statusHeight;
viewRect.origin.y = statusHeight;
self.view.frame = viewRect;
[self.view setNeedsLayout];
}
- (void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
CGRect baseFrame = self.view.frame;
// 548.0 is the full height of the view. Update as necessary.
CGFloat scale = self.view.frame.size.height / 548.0;
[self.view setTransform:CGAffineTransformMakeScale(1.0, scale)];
self.view.frame = baseFrame;
}
I used use "Vertical space - Bottom layout Guide - Button". This way, a button I have on the bottom of the screen stays in the same place when there is an in call bar and if a different screen size is used (3.5inch or 4icnh).
I am working on a chat application similar to whatsapp etc. It has a tableview in view controller and a text field and button in the bottom toolbar. I came across the various question on sliding the view upwards and using this link I managed to slide the view upwards. However I want to dismiss the keyboard and the view comes down and fits the screen .I tried using tap gesture and click on return button but nothing seems to work. How do I do make the view slide down and keyboard disappear?
Moreover how can i change the width of text field so that multiple lines can appear when the user is writing the message?
you can add tap gesture event to tableview cell and also you can use touch event method when user click on tableview then according to keyboard previous state you can display or hide keyboard. Hope this will help to u.
Use textFieldShouldReturn to resign first responder status (dismiss the keyboard) and slide the view up.
Personally I do it this way:
I register for notifications to know when the keyboard will be shown, and when it will be hidden.
When the keyboard appears, I set the view insets to include the size of the keyboard.
Slide the view up
When the keyboard will disappear, I set the insets to zero.
TextField Delegate Method to hide the keyboard when the Return button is tapped
-(BOOL)textFieldShouldReturn:(UITextField*)textField;
{
[textField resignFirstResponder];
return NO; // We do not want the UITextField to insert line-breaks.
}
Register for keyboard appear/disappear notifications
- (void)viewDidLoad
{
...
// Register for notifications for when the keyboard will appear and disappear
[self registerForKeyboardNotifications];
}
// Call this method somewhere in your view controller setup code.
- (void)registerForKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification object:nil];
}
// Called when the UIKeyboardDidShowNotification is sent.
// Original code for this part here: http://stackoverflow.com/a/16044603/4518324
- (void)keyboardWasShown:(NSNotification *)note
{
NSDictionary *userInfo = note.userInfo;
NSTimeInterval duration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
UIViewAnimationCurve curve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];
CGRect keyboardFrameEnd = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
keyboardFrameEnd = [self.view convertRect:keyboardFrameEnd fromView:nil];
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState | curve animations:^{
self.view.frame = CGRectMake(0, 0, keyboardFrameEnd.size.width, keyboardFrameEnd.origin.y);
} completion:nil];
}
- (void)keyboardWillBeHidden:(NSNotification *)note
{
NSDictionary *userInfo = note.userInfo;
NSTimeInterval duration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
UIViewAnimationCurve curve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];
CGRect keyboardFrameEnd = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
keyboardFrameEnd = [self.view convertRect:keyboardFrameEnd fromView:nil];
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState | curve animations:^{
self.view.frame = CGRectMake(0, 0, keyboardFrameEnd.size.width, keyboardFrameEnd.origin.y);
} completion:nil];
}
I have created sample code that involves resizing the view when they keyboard is shown or dismissed.
https://github.com/gingofthesouth/KeyboardHideShow
I got it right . I had another method called out when keyboard is dismissed which fit the view frame as per requirement which is View.frame-keyboard.frame.height. Thanks anyways!:)
I have some custom views with embedded table views in them. So I had to program the whole scrolling up etc when the keyboard appears myself. I've used the apple docs for that and came up with this:
- (void)viewDidLoad
{
[super viewDidLoad];
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:#selector(keyboardDidShow:)
name:UIKeyboardDidShowNotification object:nil];
[center addObserver:self selector:#selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification object:nil];
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)keyboardDidShow:(NSNotification *)notification
{
// keyboard frame is in window coordinates
NSDictionary *userInfo = [notification userInfo];
CGRect keyboardFrame = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
// convert own frame to window coordinates, frame is in superview's coordinates
CGRect ownFrame = [self.tableView.window convertRect:self.tableView.frame fromView:self.tableView.superview];
// calculate the area of own frame that is covered by keyboard
CGRect coveredFrame = CGRectIntersection(ownFrame, keyboardFrame);
// now this might be rotated, so convert it back
coveredFrame = [self.tableView.window convertRect:coveredFrame toView:self.tableView.superview];
// set inset to make up for covered array at bottom
self.tableView.contentInset = UIEdgeInsetsMake(0, 0, coveredFrame.size.height, 0);
self.tableView.scrollIndicatorInsets = self.tableView.contentInset;
}
- (void)keyboardWillHide:(NSNotification *)notification
{
self.tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
self.tableView.scrollIndicatorInsets = self.tableView.contentInset;
}
But now the not so nice thing about this (and another code I've tried, same results) is: When scrolling around the table and switching back to non-edit mode, some cells which where hidden before at the bottom of the table are immediately in the non-edit mode and not transitioning back from the indented state. Very rarely this results even in an error, that one cell remains in edit mode even though all cells have been switched back. This error disappears if I scroll the cell away and back and then it's in the correct format.
Any idea why? I've definitely narrowed it down to this code. When I comment everything out it works as it should (well of course without the scrolling when the keyboard appears :-)
I am a fairly new iPhone developer, and I am working on an iPhone app that has a view where the user needs to enter input into multiple UITextViews. There are a total of 6 UITextViews and when the view appears all the text views are visible without the need to scroll. But when the user clicks on the first text view to enter the text, the last 2 text views become hidden by the keyboard and I can't figure out how to add scrolling capability so the user will be able to scroll when the keyboard is visible. I am using a UIScrollView but currently have no code to make it work since I have tried multiple different things I have found online and none have worked. This may be an easy solution, but I am just out of ideas and have been stuck for a while. Any advice is greatly appreciated. Thanks
More Info: I am using the latest version of Xcode, developing for iPhone versions 6.1 and above. I used the Interface Builder to set up the ScrollView and the AutoLayout box is checked.
in your view did load write following lines
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardDidShow) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardDidHide) name:UIKeyboardWillHideNotification object:nil];
Make following methods.
-(void)keyboardDidHide
{
scrollview.frame = YOUR_ORIGINAL_FRAME;//You should set frame when keyboard is not there
scrollview.contentSize=scrollview.frame.size;
}
-(void)keyboardDidShow
{
CGRect r = scrollview.frame;
scrollview.contentSize=scrollview.frame.size;
r.size.height - = 216;//216 is keyboard height for iPhone.
scrollview.frame = r;
}
-(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
/* this returns the keyboard when user click on return button which is reside on keyboard */
if([text isEqualToString:#"\n"])
{
[textView resignFirstResponder];
[yourscrollview setContentOffset:CGPointMake(0,0)animated:YES];
}
return YES;
}
-(void)textViewDidEndEditing:(UITextView *)textView
{
/* it used for hide keyboard and set all control on their original position */
}
-(void)textViewDidBeginEditing:(UITextView *)textView
{
/* depending upon condition it will scroll the textview so textview can't reside behind the keyboard */
[yourscrollview setContentOffset:CGPointMake(0,textView.center.y-80)animated:YES];
}
above 80 i was defined because my requirement is to take textview that much up when keyboard appears you can put a value which is suitable to your requirements
Follow 2 simple steps as following
From storyboard/xib, adjust the frame for your scrollview and keep
height as screen size.
Within your viewcontroller apply the contentsize for your view like,
<scrollview>.contentSize=CGSizeMake(320, 700);
You will be able to see your entire scrollview on scrolling.
Use following link to move textview or textfield up and down automatically when keyboard appears
https://github.com/michaeltyson/TPKeyboardAvoiding
this link contains demo project. you can use this as you requirement
i hope this will help you.
You could do it this way:
// In View First add keyboard appearance and disappearance Notifications
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide) name:UIKeyboardWillHideNotification object:nil];
// Now inside this selector method
-(void)keyboardWillShow:(NSNotification *)notify
{
if (!notify) {
return;
}
NSDictionary *userInfo = [notify userInfo];
NSValue *keyboardEndFrame = ([userInfo objectForKey:UIKeyboardFrameEndUserInfoKey]);
CGRect endFrame = keyboardEndFrame.CGRectValue;
// Change the frame of the view to its parent
CGRect loginViewFrame = [loginView.superview convertRect:loginView.frame fromView:loginView];
// Check the keyboard covers the view
if (CGRectGetMinY(endFrame) < CGRectGetMaxY(loginViewFrame))
{
// If YES calculate Distance. Save this difference to animate back the view
difference = CGRectGetMaxY(loginViewFrame)- CGRectGetMinY(endFrame);
// animate that View
[self animateViewUp:YES withMovementDistance:difference];
}
}
// inside Will Hide
-(void)keyboardWillHide
{
// Animate back the view with the calculated distance
[self animateViewUp:NO withMovementDistance:difference];
}
- (void)animateViewUp:(BOOL)up withMovementDistance:(int)movementDistance
{
const float movementDuration = 0.3f;
int movement = (up ? -movementDistance : movementDistance);
[UIView animateWithDuration:movementDuration animations:^{
loginView.frame = CGRectOffset(loginView.frame, 0, movement);
}];
}
I've just found an annoying bug with the new keyboardDismissMode property of the scroll view. When using this with a text view with the value UIScrollViewKeyboardDismissModeInteractive and the keyboard is dismissed the scroll view seems to jump up to the top before it continues to decelerate.
I've filed a bug report with Apple but need a workaround. I've tried the DAKeyboardControl without the new iOS7 support which behind the scenes is using the keyboardDismissMode and it still does it which to me indicates this is a much deeper problem.
Any suggestions?
for this issue better you code with scrollviewDelegete and simply mention when you want dismiss keyboard through ResignFirstResponder
Does seem to be a bug or just a non-ideal default state. But based on the code in the test project something like the below may work after some finer tuning.
There are two problems with the sample code, one is that you aren't doing anything about the size of the text when the keyboard does appear, so you can't use or see the text under the keyboard. There are other solutions but a quick and dirty solution is to change the frame size (in a submission app I would also grab the animation info and animate the view frame change to match the keyboard animation which is beyond the scope of this question). You do that in 'willShow' or the like, and bring it back in 'didHide' or the like.
Then, the content offset is fudged when its hidden and there does appear to be some strange states while you are dragging it offscreen before and around your callbacks for hiding and scroll view changes. I just save the state and "fix" it once the keyboard goes away and I've updated the text view.
I created a few properties and an outlet in the storyboard to fudge with the text view.
- (void) viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil];
}
- (void) keyboardWillShow:(NSNotification *)notification
{
NSDictionary * info = [notification userInfo];
CGSize size = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
CGRect rect = self.textView.frame;
rect.size.height -= size.height;
self.textView.frame = rect;
}
- (void)keyboardDidHide:(NSNotification *)notification
{
NSLog(#"====== keyboardDidHide =======");
NSDictionary * info = [notification userInfo];
CGSize size = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
CGRect rect = self.textView.frame;
rect.size.height += size.height;
self.textView.frame = rect;
self.hidingKeyboard = YES;
}
- (void) scrollViewDidScroll:(UIScrollView *)scrollView
{
NSLog(#"%f", scrollView.contentOffset.y);
if(self.hidingKeyboard == YES)
{
scrollView.contentOffset = self.lastOffset;
self.hidingKeyboard = NO;
NSLog(#"====== reset =======");
}
else
self.lastOffset = scrollView.contentOffset;
}