ios force autolayout update on show keyboard - ios

So, I have this view that is just a wrapper for the happy pink photo that i want to center in the view. I've been using two spacing views in between the Top Layout Guide and the top of the view that wraps the textbox and the send button at the bottom of the screen (the white ones). From the picture below you can see that is working just fine.
Now, since this is going to be a "leave your comment" page, the user needs to pull the keyboard up, and the autolayout noeeds to be updated accordingly. I tried to call [self.view setNeedsLayout], [self.view updateConstraints], [self.view layoutIfNeeded], but none of them does the trick. All I have is this:
You might object that I did something wrong in the autolayout, but then when I rotate the screen, the layout updates as expected, resizing the 2 spacing views and keeping the happy pink picture in the center:
How can I trigger a layout update?? I'm going crazy!!
Please tell me if you need any more informations

There could be many reasons why the layout is not behaving the way you want, It could be the constraints that define the height of the two white UIViews, the priority of the vertical hugging or compression resistance of this views, etc, but I guess this two views can be the source of the problem.
So, if the only purpose of the two white UIViews is to centre the pink photo I would suggest you get rid of them, instead you can put the pink photo inside a single UIView and centre the photo with a couple of alignment constraints
As you can see there are two align to centre constraints for the imageView, and three more constraints that help in case you support landscape orientation, if you are in landscape orientation the image probably won't fit in the blue view so you can add two greater than constraints and an aspect ratio constraint.
Now, the light blue view that contains the image only have four constraints: leading, trailing, top and a horizontal space constraint to the textField wrapper, so when the keyboard appears and move the textField wrapper up, the containerView shrinks and the image moves to the centre.

Add observers to notify you when the keyboard appears or disappears to adapt your view by the following:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
Then implement these methods.
- (void)keyboardWillShow:(NSNotification*)notification
{
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
// the above is the keyboard size, implement prober view resizing as you wish, but i recommend a scrollview and you scroll it.
}
and then
- (void)keyboardWillHide:(NSNotification *)notification
{
//get everything back to original size or set the scrollview content size back to block scrolling.
}
at the end don't forget to remove yourself from being an observer for the keyboard when the view disappears
- (void)viewWillDisappear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}

Related

iPhone keyboard sizes

Is there a way to get the keyboard size programmatically before the keyboard is presented? In Objective-C
I need to set view.height constraint to be the same as keyboard.height programmatically. And it needs to happen before the keyboard is presented, so the view don't get this ugly constrain animation after the ViewController is presented.
I assume you present the keyboard by calling becomeFirstResponder on some UI component.
If the keyboard appears after your view is presented, you should check where that call is performed. Calling it in viewDidLoad or similarly early should cause the keyboard to be shown as the view animates in.
Your layout should also handle the keyboard changes properly. The keyboard size can change even after it's presented. For example the emoji/quick type keyboards are taller than the default keyboard.
You should perform your constraint changes in a combination of UIKeyboard[Will/Did]ShowNotification, UIKeyboard[Will/Did]HideNotification and UIKeyboardWillChangeFrameNotification. In your case, UIKeyboardWillShowNotification should do the trick.
The userInfo dictionary contains a lot of information about the keyboard. You find the final frame of the keyboard in UIKeyboardFrameEndUserInfoKey. If you animate the changes in your layout, you can use values in UIKeyboardAnimationCurveUserInfoKey and UIKeyboardAnimationDurationUserInfoKey to animate with the same animation as the keyboard.
- (void)viewDidLoad {
[super viewDidLoad];
// Don't forget to remove the observer when appropriate.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[self.textField becomeFirstResponder];
}
- (void)keyboardWillShow:(NSNotification *)notification {
CGFloat keyboardHeight = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
[self.viewHeightConstraint setConstant:keyboardHeight];
// You can also animate the constraint change.
}
Such setup will also work if the keyboard is presented from the get-go.

UIScrollView xcode 8 swift 3

This is my first question and I am brand new to coding.
I'm creating an app and one of the pages has a form for a user to fill out with two labels, two textfields, a switch and a "send" button.
For smaller screen sizes, some elements were disappearing, so I used a stackview, but when the keyboard comes up, it blocks the textfield which will be annoying to the user, I'm sure.
I've seen a few tutorials about adding scrollviews, but setting the height so everything fits nicely for smallest devices leaves an uncomfortably large blank area at the bottom of larger screens.
Is there a way to enable the scroll view only when it is needed? Is this what "dynamic" is for?
If your issue is with UI formatting on different sized screens, auto layout is a built in feature in xcode that addresses this. By adding constraints to your views, autolayout will do its best to resize your UI elements so that what you see in storyboard is what you get across all devices. Using this technique you may be able to avoid a scrollview altogether. Try selecting all your views, then go to Editor -> Resolve Auto Layout Issues -> Reset to Suggested Constraints, and see if that works.
Seems that you have two questions. First one is "For smaller screen sizes, some elements were disappearing". That one is answered by #Dalton Sweeney. Use Auto Layout then Reset to Suggested Constraints
I am going to answer your second question, what you are supposed to do when the keyboard covers some UIElemnts.
You don't need to change view controller, you should dynamically change view's frame when the keyboard hides/appears. I made a demo in GitHub, check the full version if you want:https://github.com/EricZhang90/IOS_Demo/tree/master/KeyboadDemo
The main workflow is following:
1) create two notifications to detect the keyboard is about to hide/appear:
- (void)viewDidLoad {
[super viewDidLoad];
NSNotificationCenter *ctr = [NSNotificationCenter defaultCenter];
[ctr addObserver:self
selector:#selector(moveKeyboardInResponseToWillShowNotification:)
name:UIKeyboardWillShowNotification
object:nil];
[ctr addObserver:self
selector:#selector(moveKeyboardInResponseToWillHideNotification:)
name:UIKeyboardWillHideNotification
object:nil];
}
2) adjust view's frame
The method takes two parameters: the first is keyboard information sent from notification center. You can get it from the method in first step. The second parameter indicates this adjustment is about to reduce or expand frame. Its value is 0 when the keyboard is about to hide, and is frame of keyboard when the keyboard is about to appear.
-(void)adjustView: (NSDictionary *)info :(CGRect)rect{
// get duration of keyboard appears/hides
CGFloat duration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue];
// get keyboard's curve
UIViewAnimationCurve curve = [[info objectForKey:UIKeyboardAnimationCurveUserInfoKey] integerValue];
[self.view layoutSubviews];
// Start to adjust frame:
// Animate:
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:duration];
[UIView setAnimationCurve:curve];
[UIView setAnimationBeginsFromCurrentState:YES];
// self.buttonLayoutConstraint is the layout constraint between bottom of view and bottom of screen(super view).
// This is the most important part.
self.buttonLayoutConstraint.constant = rect.size.height;
[self.view layoutSubviews];
[UIView commitAnimations];
}
This is what ended up working for me in terms of moving the scrollview up and out of the way when the textView was selected and activated the keyboard.
func textViewDidBeginEditing(_ textView: UITextView) {
scrollView.setContentOffset(CGPoint(x: 0, y: 50), animated: true)
}
**The 50 value was just what worked for my layout...that number may be different for you.
I also put in:
func textViewDidEndEditing(_ textView: UITextView) {
scrollView.setContentOffset(CGPoint(x: 0, y: 0), animated: true)
}
...so that the scrollview returned to normal once the user is done editing.

How To move UITextView above the keyboard in iOS8?

In My app, I have an form with contains UITableView and inside UITableview I have place Mutiple UITextField and UITextView.
Whenever i click on UITextfield or UITextView Keypad comes up.
I am able to move the TextFiled UP when user click on UITextField ones they want to enter the data.But i am now able to move the TextView up when user want to enter the data.
Following is my code:
-(void)viewDidLoad
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardFrameDidChange:)
name:UIKeyboardDidChangeFrameNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification object:nil];
}
Can anyone help me out to move the UITextView UP above the keypad?
Thanks in Advance.
You can use this library
https://github.com/michaeltyson/TPKeyboardAvoiding
It will handle with frame when show hide keyboard for uitextfiled and uitextView.
And you make sure you do like this:
Adding a "container" view in the case of a ScrollView with constraints set to the superview is also a good practice as follows: ViewController -> UIScrollView (TPKeyboardAvoidingScrollView) -> UIView (container for UI elements) -> UITextView. If you want vertical scrolling set the height constraint to be '>='.
Use IQKeyboardManager to handle this problem.
Features:
1) CODELESS, Zero Line Of Code
2) Works Automatically
3) No More UIScrollView
4) No More Subclasses
5) No More Manual Work
6) No More #imports
And its available for both languages (Swift and Objective C)

Can I set frame of particular view programatically even if Auto Layout is enabled?

Suppose I am having a view controller A having 5 views inside it like labels, buttons. I have set constraint to 4 views. But, for 5th view, case is different. In portrait, I need different x,y positions and height and width. In landscape, I need different x,y positions and height and width. So, it is not possible to define constraints for that because it's a custom. I will only have to set frame programmatically wherever I wanted my view to be placed in different orientation.
Is there any solution for that?
After detecting the orientation you can use the IBOutlets of your connected control to set the frame for example :
[myView setFrame:CGRectMake(x,y,width,height)];
I hope this helps you.
EDIT
first create a constraint in the story board or your IB then create an outlet for that constraint for ex :
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *viewHeightConstraint;
then change this constraint programmatically like :
self.viewHeightConstraint.constant = 40;
Option 1
Add this to your viewcontroller,and use it to monitor your device orientation,than change your 5th view frame
-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator{
}
Option 2
In viewDidLoad add
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(change:) name:UIDeviceOrientationDidChangeNotification object:nil];
Then in this function you can monitor orientation change
-(void)change:(UIDeviceOrientation)orientation{
}
In dealloc,remove it
-(void)dealloc{
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
}

How to pin a UIView to the bottom of its superview, but have it move when the keyboard appears?

I have a UIView with a UIView and UITableView in it. The child UIView is for composition, it has textfield and a Send button like any messenger. How can I pin/fix this child UIView to the bottom of the Superview and keep it visibly on top of the UITableView? However the child UIView needs to also rise above the keyboard when its textfield is focused.
You can do this manually. You can sign up for getting keyboard notifications.
You can the following functions
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification object:nil];
There is a very good article about this on Apple Keyboard Management with code snippets.
The answer to your question is different for AutoLayout and for AutoResizingMasks (struts and springs) style layout.
For AutoLayout, the default for Xcode 6, what you would do would be to create a constraint to pin your view to the bottom of it's superview, as normal. Then you'd select that constraint in IB and control-drag it into the header file of your view controller, and create an IBOutlet for the constraint.
You can then write a notification handler for the keyboard will show notification, and in that handler, change the constant (offset) of your constraint property. The final step is to put a call to your superview's layoutIfNeeded method inside a UIView animation block. That causes the layout change from updating the constraint to be animated.
You then do the opposite for a keyboard will hide notification.
If you're doing struts-and-springs style layout, it's similar but simpler. You just create an outlet to the view that you want to move, and then make your keyboard will show notification handler use a UIView animation to animate a change to the view's center property .

Resources