UITextField:当键盘出现时移动视图
我目前正在一个单一的视图,有多个UITextFieldsinputiPhone应用程序。 当键盘显示时,它覆盖底部的文本框。 所以我添加了相应的textFieldDidBeginEditing:
方法,将视图向上移动,效果很好:
- (void)textFieldDidBeginEditing:(UITextField *)textField { if ( ( textField != inputAmount ) && ( textField != inputAge ) ) { NSTimeInterval animationDuration = 0.300000011920929; CGRect frame = self.view.frame; frame.origin.y -= kOFFSET_FOR_KEYBOARD; frame.size.height += kOFFSET_FOR_KEYBOARD; [UIView beginAnimations:@"ResizeForKeyboard" context:nil]; [UIView setAnimationDuration:animationDuration]; self.view.frame = frame; [UIView commitAnimations]; } }
如果消息的来源是键盘显示时可见的文本字段之一,则该方法将检查该消息的来源,如果不是,则会将视图向上移动。
我还添加了textFieldDidEndEnditing:
方法,该方法再次移动视图(并根据更改的input更新一些模型对象):
- (void)textFieldDidEndEditing:(UITextField *)textField { if ( ( textField != inputMenge ) && ( textField != inputAlter ) ) { NSTimeInterval animationDuration = 0.300000011920929; CGRect frame = self.view.frame; frame.origin.y += kOFFSET_FOR_KEYBOARD; frame.size.height -= kOFFSET_FOR_KEYBOARD; [UIView beginAnimations:@"ResizeForKeyboard" context:nil]; [UIView setAnimationDuration:animationDuration]; self.view.frame = frame; [UIView commitAnimations]; } // Additional Code }
但是,这个解决scheme有一个简单的缺陷:当我完成编辑其中一个“隐藏”的文本字段并触摸另一个文本字段时,键盘消失,视图向下移动,视图再次移动,键盘再次出现。
是否有可能使键盘在两次编辑(“隐藏”文本字段)之间消失并重新出现 – 以便视图仅在所选文本字段从键盘隐藏的字符变为不能隐藏的字符)?
这个解决scheme是基于ComSubVie的。
优点:
- 它支持设备旋转 – 适用于所有方向;
- 它不会对animation持续时间和曲线的值进行硬编码,而是从键盘通知中读取它们。
- 它利用
UIKeyboardWillShowNotification
而不是UIKeyboardDidShowNotification
来同步键盘animation和自定义动作; - 它不使用已弃用的
UIKeyboardBoundsUserInfoKey
; - 它处理由于按国际键的键盘大小调整;
- 通过注销键盘事件修复内存泄漏;
- 所有键盘处理代码被封装在一个单独的类 –
KBKeyboardHandler
; - 灵活性 –
KBKeyboardHandler
类可以很容易地扩展/修改,以更好地适应特定的需求;
限制:
- 适用于iOS 4及以上版本,需要较小的修改才能支持旧版本;
- 它适用于具有单个
UIWindow
应用程序。 如果您使用多个UIWindows,则可能需要修改retrieveFrameFromNotification:
方法。
用法:
在你的项目中包含KBKeyboardHandler.h,KBKeyboardHandler.m和KBKeyboardHandlerDelegate.h。 在您的视图控制器中实现KBKeyboardHandlerDelegate
协议 – 它由一个单一的方法组成,当显示键盘,隐藏或改变其大小时,将调用这个方法。 实例化KBKeyboardHandler
并设置它的委托(通常是self)。 请参阅下面的示例MyViewController
。
KBKeyboardHandler.h :
#import <Foundation/Foundation.h> #import <UIKit/UIKit.h> @protocol KBKeyboardHandlerDelegate; @interface KBKeyboardHandler : NSObject - (id)init; // Put 'weak' instead of 'assign' if you use ARC @property(nonatomic, assign) id<KBKeyboardHandlerDelegate> delegate; @property(nonatomic) CGRect frame; @end
KBKeyboardHandler.m :
#import "KBKeyboardHandler.h" #import "KBKeyboardHandlerDelegate.h" @implementation KBKeyboardHandler - (id)init { self = [super init]; if (self) { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; } return self; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; [super dealloc]; } @synthesize delegate; @synthesize frame; - (void)keyboardWillShow:(NSNotification *)notification { CGRect oldFrame = self.frame; [self retrieveFrameFromNotification:notification]; if (oldFrame.size.height != self.frame.size.height) { CGSize delta = CGSizeMake(self.frame.size.width - oldFrame.size.width, self.frame.size.height - oldFrame.size.height); if (self.delegate) [self notifySizeChanged:delta notification:notification]; } } - (void)keyboardWillHide:(NSNotification *)notification { if (self.frame.size.height > 0.0) { [self retrieveFrameFromNotification:notification]; CGSize delta = CGSizeMake(-self.frame.size.width, -self.frame.size.height); if (self.delegate) [self notifySizeChanged:delta notification:notification]; } self.frame = CGRectZero; } - (void)retrieveFrameFromNotification:(NSNotification *)notification { CGRect keyboardRect; [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardRect]; self.frame = [[UIApplication sharedApplication].keyWindow.rootViewController.view convertRect:keyboardRect fromView:nil]; } - (void)notifySizeChanged:(CGSize)delta notification:(NSNotification *)notification { NSDictionary *info = [notification userInfo]; UIViewAnimationOptions curve; [[info objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&curve]; NSTimeInterval duration; [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&duration]; void (^action)(void) = ^{ [self.delegate keyboardSizeChanged:delta]; }; [UIView animateWithDuration:duration delay:0.0 options:curve animations:action completion:nil]; } @end
KBKeyboardHandlerDelegate.h :
@protocol KBKeyboardHandlerDelegate - (void)keyboardSizeChanged:(CGSize)delta; @end
示例MyViewController.h :
@interface MyViewController : UIViewController<KBKeyboardHandlerDelegate> ... @end
示例MyViewController.m :
@implementation MyViewController { KBKeyboardHandler *keyboard; } - (void)dealloc { keyboard.delegate = nil; [keyboard release]; [super dealloc]; } - (void)viewDidLoad { [super viewDidLoad]; keyboard = [[KBKeyboardHandler alloc] init]; keyboard.delegate = self; } - (void)viewDidUnload { [super viewDidUnload]; keyboard.delegate = nil; [keyboard release]; keyboard = nil; } - (void)keyboardSizeChanged:(CGSize)delta { // Resize / reposition your views here. All actions performed here // will appear animated. // delta is the difference between the previous size of the keyboard // and the new one. // For instance when the keyboard is shown, // delta may has width=768, height=264, // when the keyboard is hidden: width=-768, height=-264. // Use keyboard.frame.size to get the real keyboard size. // Sample: CGRect frame = self.view.frame; frame.size.height -= delta.height; self.view.frame = frame; }
更新:修正了iOS 7的警告,感谢@ weienv。
我刚刚解决了这个问题。 解决scheme是UIKeyboardDidShowNotification
和UIKeyboardDidHideNotification
观察者与上面的textFieldDidBeginEditing:
和textFieldDidEndEditing:
方法的组合。
您需要三个额外的variables,一个用于存储当前选定的UITextField(我已命名为activeField),一个用于指示当前视图是否已移动,另一个用于指示是否显示键盘。
这是两个UITextField
委托方法现在的样子:
- (void)textFieldDidBeginEditing:(UITextField *)textField { activeField = textField; } - (void)textFieldDidEndEditing:(UITextField *)textField { activeField = nil; // Additional Code }
加载视图时,会创build以下两个观察者:
- (void)viewDidLoad { // Additional Code [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:) name:UIKeyboardDidShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasHidden:) name:UIKeyboardDidHideNotification object:nil]; }
相应的实现方法如下:
- (void)keyboardWasShown:(NSNotification *)aNotification { if ( keyboardShown ) return; if ( ( activeField != inputAmount ) && ( activeField != inputAge ) ) { NSDictionary *info = [aNotification userInfo]; NSValue *aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey]; CGSize keyboardSize = [aValue CGRectValue].size; NSTimeInterval animationDuration = 0.300000011920929; CGRect frame = self.view.frame; frame.origin.y -= keyboardSize.height-44; frame.size.height += keyboardSize.height-44; [UIView beginAnimations:@"ResizeForKeyboard" context:nil]; [UIView setAnimationDuration:animationDuration]; self.view.frame = frame; [UIView commitAnimations]; viewMoved = YES; } keyboardShown = YES; } - (void)keyboardWasHidden:(NSNotification *)aNotification { if ( viewMoved ) { NSDictionary *info = [aNotification userInfo]; NSValue *aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey]; CGSize keyboardSize = [aValue CGRectValue].size; NSTimeInterval animationDuration = 0.300000011920929; CGRect frame = self.view.frame; frame.origin.y += keyboardSize.height-44; frame.size.height -= keyboardSize.height-44; [UIView beginAnimations:@"ResizeForKeyboard" context:nil]; [UIView setAnimationDuration:animationDuration]; self.view.frame = frame; [UIView commitAnimations]; viewMoved = NO; } keyboardShown = NO; }
此代码现在按预期工作。 键盘只有在完成button被按下时才被解除,否则它将保持可见状态,视图不会被移动。
另外需要注意的是,我认为可以通过询问NSNotification
对象来dynamic获取animationDuration
,因为我已经使用了类似的解决scheme,但没有得到它的工作(现在是这样)。
这个视图控制器必须是UITextView委托,你必须在viewdidload中设置self.textview.delegate = self
-(void) textViewDidBeginEditing:(UITextView *)textView { NSLog(@"%f",self.view.frame.origin.y); [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration:0.25f]; CGRect frame = self.view.frame; frame.origin.y =frame.origin.y -204; [self.view setFrame:frame]; [UIView commitAnimations]; } -(void) textViewDidEndEditing:(UITextView *)textView { [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration:0.25f]; CGRect frame = self.view.frame; frame.origin.y = frame.origin.y + 204; [self.view setFrame:frame]; [UIView commitAnimations]; }
我得到你的问题只是简单的事情只是给UIScrollviewsockets。 为视图中的每个文本字段设置唯一的Tag属性。
-(void)textFieldDidBeginEditing:(UITextField *)textField { switch (textField.tag) { case 2: //can be your textfiled tag { CGPoint scrollPoint = CGPointMake(0, yourtextfield.frame.origin.y-150); //set figure y-150 as per your comfirt [scrollview setContentOffset:scrollPoint animated:YES]; }break; case 3: { CGPoint scrollPoint = CGPointMake(0, yourtextfield.frame.origin.y-180); //set figure y-180 as per your comfirt [scrollview setContentOffset:scrollPoint animated:YES]; }break; ... } } -(void)textFieldDidEndEditing:(UITextField *)textField{ if(textField.tag==3){ [scrollview setContentOffset:CGPointZero animated:YES]; } //set the last textfield when you want to disappear keyboard. }
Write below code in your view controller. tbl is your table view. -(void)viewWillAppear:(BOOL)animated{ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; } -(void) viewWillDisappear:(BOOL)animated { [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillChangeFrameNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil]; } #pragma mark - Keyboard Methods -(void)keyboardWillShow:(NSNotification *)notification { // 375 × 667 ( 750 × 1334 ) iPhone 6 //414 × 736 CGRect keyboardRect = [[[notification userInfo] valueForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; int H = [[UIScreen mainScreen] bounds].size.height - 64- 20 -keyboardRect.size.height; [UIView animateWithDuration:0.5 animations:^{ tbl.contentInset = UIEdgeInsetsMake(tbl.contentInset.top, tbl.contentInset.left, H, tbl.contentInset.right); }]; } -(void)keyboardWillChangeFrame:(NSNotification *)notification { CGRect keyboardRect = [[[notification userInfo] valueForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; // int H = IS_IPHONE_5?504-keyboardRect.size.height:416-keyboardRect.size.height; int H = [[UIScreen mainScreen] bounds].size.height - 64- 20 -keyboardRect.size.height; [UIView animateWithDuration:0.5 animations:^{ // scroll.frame = rect; tbl.contentInset = UIEdgeInsetsMake(tbl.contentInset.top, tbl.contentInset.left, H, tbl.contentInset.right); }]; } -(void)keyboardWillHide:(NSNotification *)notification { [UIView animateWithDuration:0.3 animations:^{ // scroll.frame = rect; tbl.contentInset = UIEdgeInsetsMake(tbl.contentInset.top, tbl.contentInset.left, 0, tbl.contentInset.right); }]; }
相当简单的解决scheme,适用于所有屏幕尺寸
首先,您必须将UITextFieldsembedded到UIScrollView。 在我的情况下,我有几个UITextFields和一个UITextView。
那么你必须从UITextFieldDelegate,UITextViewDelegateinheritance。
class SettingsVC: UIViewController, UITextFieldDelegate, UITextViewDelegate
将textfield和textview的委托分配给self。
fullNameTextField.delegate = self usernameTextField.delegate = self websiteTextField.delegate = self profileDescription.delegate = self
然后使用这个代码:
var editingTextInput: UIView! override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardShown(notification:)), name: NSNotification.Name.UIKeyboardDidShow, object: nil) } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardDidShow, object: nil) } func keyboardShown(notification: NSNotification) { if let infoKey = notification.userInfo?[UIKeyboardFrameEndUserInfoKey], let rawFrame = (infoKey as AnyObject).cgRectValue { let keyboardFrame = view.convert(rawFrame, to: view) let editingTextInputFrame = self.editingTextInput.convert(self.editingTextInput.frame, to: view) if editingTextInputFrame.maxY > keyboardFrame.minY{ let diff = keyboardFrame.minY - editingTextInputFrame.maxY containerScrollView.setContentOffset(CGPoint(x: 0, y: -diff), animated: true) } } } func textFieldDidBeginEditing(_ textField: UITextField) { self.editingTextInput = textField } func textViewDidBeginEditing(_ textView: UITextView) { self.editingTextInput = textView } func textFieldDidEndEditing(_ textField: UITextField) { containerScrollView.setContentOffset(CGPoint.zero, animated: true) } func textViewDidEndEditing(_ textView: UITextView) { containerScrollView.setContentOffset(CGPoint.zero, animated: true) }