[英]How to resize UITextView on iOS when a keyboard appears?
There's UITextView
inserted into tab in UITabBarController
(on the iPhone). 在
UITabBarController
(在iPhone上)的选项卡中插入了UITextView
。
UITextView
with a lot of lines. UITextView
。 What's happen? 发生了什么? The keyboard hide a half of
UITextView
with cursor. 键盘用光标隐藏了一半的
UITextView
。 Can't edit the text as the result. 无法编辑文本作为结果。
How to resolve the issue for all Apple mobile devices (with different screen resolution)? 如何解决所有Apple移动设备(具有不同屏幕分辨率)的问题? Thanks a lot for help!
非常感谢您的帮助!
The best result was reached by the following code. 以下代码达到了最佳结果。 Also don't forget to set background color to
UIView
and place UITextView
before other top-screen controls (eg UITabBar). 另外不要忘了背景色设置为
UIView
并将UITextView
前等顶级屏幕控制(如UITabBar)。
Editing of a text in the end still isn't perfect now. 最后编辑文本仍然不完美。 You may try to improve.
你可以尝试改进。
FirstViewController.h:
@interface FirstViewController : UIViewController {
IBOutlet UIBarButtonItem *buttonDone;
IBOutlet UITextView *textView;
UITabBarController* tabBarController; // set from superview in AppDelegate (MainWindow.xib)
}
@property (nonatomic, retain) UITabBarController* tabBarController;
FirstViewController.m:
@synthesize tabBarController;
- (void)viewDidAppear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShown:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)viewWillDisappear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)moveTextViewForKeyboard:(NSNotification*)aNotification up:(BOOL)up {
NSDictionary* userInfo = [aNotification userInfo];
NSTimeInterval animationDuration;
UIViewAnimationCurve animationCurve;
CGRect keyboardEndFrame;
[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];
CGRect newFrame = textView.frame;
CGRect keyboardFrame = [self.view convertRect:keyboardEndFrame toView:nil];
keyboardFrame.size.height -= tabBarController.tabBar.frame.size.height;
newFrame.size.height -= keyboardFrame.size.height * (up?1:-1);
textView.frame = newFrame;
[UIView commitAnimations];
}
- (void)keyboardWillShown:(NSNotification*)aNotification
{
buttonDone.enabled = true;
[self moveTextViewForKeyboard:aNotification up:YES];
}
- (void)keyboardWillHide:(NSNotification*)aNotification
{
buttonDone.enabled = false;
[self moveTextViewForKeyboard:aNotification up:NO];
}
PS It's hard to code for iOS without stackoverflow... PS没有stackoverflow就很难为iOS编码......
With Auto Layout, it's much easier (provided you understand Auto Layout) to handle: 使用自动布局,您可以更轻松地(只要您了解自动布局)处理:
Instead of trying to identify and resize the affected views, you simply create a parent frame for all your view's contents. 您只需为所有视图的内容创建父框架,而不是尝试识别和调整受影响的视图的大小。 Then, if the kbd appears, you resize the frame, and if you've set up the constraints properly, the view will re-arrange all its child views nicely.
然后,如果出现kbd,则调整框架大小,如果已正确设置约束,视图将很好地重新排列其所有子视图。 No need to fiddle with lots of hard-to-read code for this.
无需为此提供大量难以阅读的代码。
In fact, in a similar question I found a link to this excellent tutorial about this technique. 事实上,在类似的问题中,我找到了关于这种技术的优秀教程的链接。
I ran into several issues trying to get my text view to scroll and animate correctly for both iOS 7 and iOS 8, and with the new QuickType feature. 我遇到了几个问题,试图让我的文本视图能够正确地滚动和动画,适用于iOS 7和iOS 8,以及新的QuickType功能。 At first I was focused on animating the scroll view insets, but the behaviour differed between iOS 7 and 8 and could not get it working correctly for both.
起初我专注于动画滚动视图插图,但iOS 7和8之间的行为不同,并且无法使两者都正常工作。
Then I realized I can simplify things by just focusing on the frame and this worked for me with a lot more simple code. 然后我意识到我可以通过专注于框架简化事情,这对我来说有更多简单的代码。 In summary:
综上所述:
UIKeyboardDidChangeFrameNotification
(this will notify when the QuickType is shown/hidden as well). UIKeyboardDidChangeFrameNotification
(这将在QuickType显示/隐藏时通知)。 Here is some code that illustrates the above: 以下是一些说明上述内容的代码:
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidChangeFrameWithNotification:) name:UIKeyboardDidChangeFrameNotification object:nil];
}
- (void)keyboardDidChangeFrameWithNotification:(NSNotification *)notification {
CGFloat keyboardVerticalIncrease = [self keyboardVerticalIncreaseForNotification:notification];
[self animateTextViewFrameForVerticalOffset:keyboardVerticalIncrease];
}
- (CGFloat)keyboardVerticalIncreaseForNotification:(NSNotification *)notification {
CGFloat keyboardBeginY = [notification.userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue].origin.y;
CGFloat keyboardEndY = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue].origin.y;
CGFloat keyboardVerticalIncrease = keyboardBeginY - keyboardEndY;
return keyboardVerticalIncrease;
}
- (void)animateTextViewFrameForVerticalOffset:(CGFloat)offset {
CGFloat constant = self.bottomConstraint.constant;
CGFloat newConstant = constant + offset;
self.bottomConstraint.constant = newConstant;
[self.view layoutIfNeeded];
[UIView animateWithDuration:0.5 animations:^{
[self.view layoutIfNeeded];
}];
}
A quick note on the animation. 关于动画的快速说明。 I used Autolayout so I chose to animate the text view's NSAutoLayoutConstraint, not the frame directly.
我使用了Autolayout,因此我选择为文本视图的NSAutoLayoutConstraint设置动画,而不是直接设置框架。 And to do this, I call
[self.view layoutIfNeeded]
before and inside the animation block. 为此,我在动画块之前和之内调用
[self.view layoutIfNeeded]
。 This is the correct way of animating constraints. 这是动画约束的正确方法。 I found this tip here .
我在这里找到了这个提示。
It's worth noting that the upvoted answer only works if the device is in portrait mode (and not upside down), in other modes the bounds go wrong. 值得注意的是,只有当设备处于纵向模式(而不是颠倒)时,upvoted答案才有效,在其他模式下,边界出错。 I believe that you could sort this by using bounds to fix, but I couldn't get that to work so the below adjustment worked for me:
我相信你可以通过使用边界来修复它,但我无法让它工作,所以下面的调整对我有用:
- (void)moveTextViewForKeyboard:(NSNotification*)aNotification up:(BOOL)up {
NSDictionary* userInfo = [aNotification userInfo];
NSTimeInterval animationDuration;
UIViewAnimationCurve animationCurve;
CGRect keyboardEndFrame;
[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];
CGRect newFrame = self.view.frame;
if (keyboardEndFrame.size.height >keyboardEndFrame.size.width)
{ //we must be in landscape
if (keyboardEndFrame.origin.x==0)
{ //upside down so need to flip origin
newFrame.origin = CGPointMake(keyboardEndFrame.size.width, 0);
}
newFrame.size.width -= keyboardEndFrame.size.width * (up?1:-1);
} else
{ //in portrait
if (keyboardEndFrame.origin.y==0)
{
//upside down so need to flip origin
newFrame.origin = CGPointMake(0, keyboardEndFrame.size.height);
}
newFrame.size.height -= keyboardEndFrame.size.height * (up?1:-1);
}
self.view.frame = newFrame;
[UIView commitAnimations];
}
- (void)registerKeyboardNotifications
{
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardDidShowNotification
object:nil];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
}
- (void)unregisterKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
-(void) keyboardWillHide:(NSNotification *)note
{
//adjust frame
}
-(void) keyboardWillShow:(NSNotification *)note
{
//adjust frame
}
and unregister Notification too in the dealloc 并且在dealloc中也注销了Notification
- (void)unregisterKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
Years gone, the question is still actual. 多年过去了,这个问题仍然存在。 Apple definitely should handle all these things itself.
Apple绝对应该自己处理所有这些事情。 But it doesn't.
但事实并非如此。 Here's the new solution based on the official Apple's documentation plus bug fixes.
这是基于官方Apple 文档和错误修复的新解决方案。 It supports iOS 8, iOS 9, inputAccessoryView and is ready for new versions of iOS and new devices.
它支持iOS 8,iOS 9,inputAccessoryView,可以用于新版本的iOS和新设备。
/* Apple's solution to resize keyboard but with accessory view support */
- (void)keyboardDidShow:(NSNotification*)aNotification {
NSDictionary* info = [aNotification userInfo];
CGRect keyboardFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
double keyboardHeight = [[UIScreen mainScreen] bounds].size.height - keyboardFrame.origin.y;
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardHeight, 0.0);
editor.contentInset = contentInsets;
editor.scrollIndicatorInsets = contentInsets;
}
- (void)keyboardWillHide:(NSNotification*)aNotification {
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
editor.contentInset = contentInsets;
editor.scrollIndicatorInsets = contentInsets;
// button to hide the keyboard
buttonDone.enabled = false;
}
/* Fix issues with size classes and accessory view */
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
// fix incorrect size of the inputAccessoryView when size class changed
// willTransitionToTraitCollection and traitCollectionDidChange can't help us
if (editor && editor.inputAccessoryView && !editor.inputAccessoryView.hidden) {
[editor resignFirstResponder];
}
}
/* Hide accessory view if a hardware keyboard is present */
#define gThresholdForHardwareKeyboardToolbar 160.f // it's minimum height of the software keyboard on iPhone 4 in landscape mode
- (bool)isExternalKeyboard:(NSNotification*)aNotification {
NSDictionary* info = [aNotification userInfo];
CGRect keyboardFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
double keyboardHeight = [[UIScreen mainScreen] bounds].size.height - keyboardFrame.origin.y;
return keyboardHeight < gThresholdForHardwareKeyboardToolbar;
}
- (void)keyboardWillShow:(NSNotification*)aNotification {
if ([self isExternalKeyboard:aNotification]) {
// hardware keyboard is present
if (editor && editor.inputAccessoryView) {
editor.inputAccessoryView.hidden = true;
}
} else {
// only on-screen keyboard
if (editor && editor.inputAccessoryView) {
editor.inputAccessoryView.hidden = false;
}
}
// button to hide the keyboard
buttonDone.enabled = true;
}
First add a few keyboard methods to the NSNotificationCenter
defaultCenter 首先将一些键盘方法添加到
NSNotificationCenter
defaultCenter
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification object:self.view.window];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification object:self.view.window];
then you can change the sizes: 然后你可以改变大小:
- (void)keyboardWillShow:(NSNotification *)notif
{
[thetextView setFrame:CGRectMake(20, 49, 280, 187)]; //Or where ever you want the view to go
}
- (void)keyboardWillHide:(NSNotification *)notif
{
[thetextView setFrame:CGRectMake(20, 49, 280, 324)]; //return it to its original position
}
As a follow-up, the technique where you update the frame when the keyboard notification occurs does not work for iOS 7. For an alternative solution, see the following: 作为后续操作,在键盘通知发生时更新帧的技术对iOS 7不起作用。对于替代解决方案,请参阅以下内容:
How to re-size UITextView when keyboard shown with iOS 7 当iOS 7显示键盘时,如何重新调整UITextView的大小
I tried the best answer here however I found a problem in it. 我在这里尝试了最好的答案但是我发现了一个问题。 If you have another text field on the same page, you click the text field, show the keyboard.
如果您在同一页面上有另一个文本字段,则单击文本字段,显示键盘。 You will notice the text view shrinks.
您会注意到文本视图缩小了。 However, if you click the text view now, you will notice the text view size shrinks again while it should not.
但是,如果现在单击文本视图,您会注意到文本视图大小再次缩小,而不应该。
My solution to this problem is to maintain a property in view controller representing keyboard state(shown/hide). 我对这个问题的解决方案是在视图控制器中维护一个表示键盘状态的属性(显示/隐藏)。 If the keyboard is current visible, the text view should not be shrunk.
如果键盘当前可见,则不应缩小文本视图。 In case you are using keyboards of different sizes for different text inputs, you should also maintain the old keyboard size.
如果您使用不同大小的键盘进行不同的文本输入,您还应该保持旧的键盘大小。
Be aware that this solution also didn't take different orientation into account, which may affect the way you calculate the size of text view. 请注意,此解决方案也没有考虑不同的方向,这可能会影响您计算文本视图大小的方式。
@implementation MyViewController {
BOOL keyboardShown;
NSInteger keyboardHeight;
}
- (void)moveTextViewForKeyboard:(NSNotification*)aNotification up: (BOOL) up{
NSDictionary* userInfo = [aNotification userInfo];
NSTimeInterval animationDuration;
UIViewAnimationCurve animationCurve;
CGRect keyboardEndFrame;
[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];
CGRect newFrame = self.textView.frame;
CGRect keyboardFrame = [self.view convertRect:keyboardEndFrame toView:nil];
NSInteger oldHeight = self->keyboardShown ? self->keyboardHeight : 0;
NSInteger newHeight = up ? keyboardFrame.size.height : 0;
NSInteger change = oldHeight - newHeight;
self->keyboardShown = up;
self->keyboardHeight = keyboardFrame.size.height;
newFrame.size.height += change;
self.textView.frame = newFrame;
[UIView commitAnimations];
}
简而言之,注册键盘通知并在收到通知后进行重新调整大小的工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.