I made a custom keyboard view and linked it to the inputView property of a UITextField.
Is there a way to change the height of a custom inputView when orientation changes and have the frame change animated smoothly just like the system keyboard?
My keyboard size is 768x272 and when the device goes landscape the size becomes 1024x272, but I want to make it bigger like 1024x372. If I change the frame with the code below when I get UIDeviceOrientationDidChangeNotification, the change animation is not smooth.
textField.inputView.frame = CGRectMake(0,0,1024,372);
Per Apple documentation for UIResponder.inputView:
"If UIKit encounters an input view with a UIViewAutoresizingFlexibleHeight value in its autoresizing mask, it changes the height to match the keyboard."
So if you want customized height, you shouldn't specify UIVieAutoresizingFlexibleHeight mask.
After many experiments, I found the best answer to my own question. A short answer is change frame when you get UIKeyboardDidHideNotification.
Custom inputView is embedded in another view controlled by the system called UIPeripheralHostView.
So changing the custom inputView at wrong time is not reflected immediately or shows an ugly layout at best.
When the device rotates, the system briefly hides the keyboard, then performs a rotation animation of the keyboard from old orientation to new orientation. I think the animation block is inserted somewhere between two notifications UIKeyboardDidHideNotification and UIKeyboardWillShowNotification. These notifications are coupled with UIKeyboardWillChangeFrameNotification. The "frame" in this notification actually means the frame of UIPeripheralHostView.
So changing the frame of my input view when I get UIKeyboardDidHideNotification gives the system a chance to adjust the frame of UIPeripheralHostView before the animation starts, resulting in smooth transition from short keyboard to tall keyboard during orientation change.
This works in iOS 5. But Apple may change the practice in the future.
Related
I can get the keyboard's dimension after its displayed from the notification, BUT I would like to position my textFields so that I don't have to scroll them when the keyboard appears. To achieve this I should know the keyboard's dimension BEFORE it's even displayed.
Is this possible on iOS?
You can use a class where this all things are handled by default. Just you have to use scroll view for this.
TPKeyboardAvoidingScrollView
See if it's useful and fulfill your requirement.
I am trying to use the UITableView.keyboardDismissMode = UIScrollViewKeyboardDismissMode.Interactive, to be able to drag my keyboard up and down. However I can't find any way to track the keyboard frame to update my tableView frame and messaging view. I am simply trying to replicate the standard iMessage behaviour. Given the name, I would have thought that UIKeyboardWillChangeFrameNotification would have been perfect for tracking the keyboard frame changes, but it only notifies when the gesture ends and the keyboard animates up or down.
I'm not sure if this will work but you could try to track the drag progress via the panGesture property on UIScrollView in your tableView. It wouldn't be a direct tracking of the keyboard frame, but if you know the keyboard's height and the progress/offset of the pan, you might be able to math your way around the problem.
The best approach for interactive dismissal is to use the "UIKeyboardDidShowNotification" and "UIKeyboardWillHideNotification" system notifications. When the selector is called you update the table's bottom inset. NOT the constraints. Updating the inset will give you a beautiful smooth keyboard dismissal experience.
I'm having trouble reliably getting the actual height of the keyboard. I'm adding a custom toolbar that is meant to be placed directly above the keyboard. To do so with layout constraints, I've added a static space constraint between the bottom of the screen and the bottom of the toolbar. When the keyboard is displayed, I modify this constraint to be the height of the keyboard, which varies quite a bit in iOS 8.
To resize the spacer, I currently use the following method that gets fired on UIKeyboardDidShowNotification
-(void)keyboardDidShow:(NSNotification*)notification
{
CGFloat height = [[notification.userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].height;
self.shimConstraint.constant = height;
[self.view layoutIfNeeded];
}
This does resize the constraint correctly sometimes, but often the keyboard height returned is entirely incorrect. What is the best way to reliably get the height of the keyboard once it is displayed?
EDIT: The application allows the user to switch between a number of different input fields. Some of them have autocorrect disabled, so the autocorrect bar may or may not be hidden, and incorrect heights are returned when switching fields.
The way you are doing it is correct but you might want to use UIKeyboardFrameEndUserInfoKey instead of UIKeyboardFrameBeginUserInfoKey. The end user key is the frame of the keyboard when it is done animating and on the screen, thus you know it will be that frame, while the begin key might not always match what the keyboard frame will be when it is shown.
There might also need to be extra considerations on orientation of the device, I have not looked into that, but for portrait, it should work.
The correct way to do this is to use the inputAccesorryView property of the UITextField.
The inputAccessoryView is automatically added above the keyboard regardless of keyboard size.
As the documentation states:
The default value of this property is nil. Assigning a view to this property causes that view to be displayed above the standard system keyboard (or above the custom input view if one is provided) when the text field becomes the first responder. For example, you could use this property to attach a custom toolbar to the keyboard
See more information here
https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/InputViews/InputViews.html
You might need to do [self.view setNeedsLayout] instead of [self.view layoutIfNeeded].
I have a scrollview which cointains a uitextfield, a uitextview and two label
The uitextfield and the two label don't scroll.
In portrait mode all works fine.
In landscape mode, I resize the scroll view in the way that the labels are not visible, only title and textview remains, but I have a problem when the user try to insert the text in the textview. The current position is under the title, so the user cannot see what he/she insert. I would lower it.
Using the autosizing masks in IB, don't change the situation: I have to make flexible only the uitextview.
What can I try?
I thought that scrollRangeToVisible could help me, but nothing.
Try using
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration {
or
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
in your view controller to place your uiTextView where you need it depending on the orientation. Change the textview's frame to something that works visually. I think the first method ignores IB's resizing masks, so you have to set coordinates for your objects' frames using CGRectMake. The second method will animate the rotation as per the resizing masks, but then will "all of a sudden" move the objects to where you specified their frames to be (again using CGRectMake).
iPad app; I'm trying to resize my view when the keyboard appears. It amounts to calling this code at appropriate times:
CGRect adjustedFrame = self.frame;
adjustedFrame.size.height -= keyboardFrame.size.height;
[self setFrame:adjustedFrame];
Using this technique for a view contained in a uisplitview-based app works in all 4 orientations, but I've since discovered that a vanilla uiview-based app does not work.
What happens is that apparently the uisplitview is smart enough to convert the coordinates of its subviews (their frame) such that the origin is in the "viewer's top left" regardless of the orientation. However, a uiview is not able to correctly report these coordinates. Though the origin is reported as (0,0) in all orientations, the view's effective origin is always as if the ipad were upright.
What is weird about this is that the view correctly rotates and draws, but it always originates in the literal device top left. How can I get the view to correctly make its origin the "top left" to the viewer, not the device's fixed top left? What am I missing? Please, for something so trivial I've spent about 6 hours on this already with every brute force technique and research angle I could think of.
This is the original source which doesn't work in this case:
move up UIToolbar
OK, I don't know what the ACTUAL answer is to the original question, but I can say with certainty that one way to resolve the issue is to always ensure that you don't manipulate a viewController's view directly. Always wrap your view inside a container view inside the main "view", then have that container view adjust its position etc as needed. Works exactly as the splitview does, probably because in both cases now the view in question is a subview of the main "view". What a relief!