[英]Move UIView up when the keyboard appears in iOS
我有一個 UIView,它不在 UIScrollView 里面。 當鍵盤出現時,我想向上移動我的視圖。 在我嘗試使用此解決方案之前: 當鍵盤存在時,如何使 UITextField 向上移動? .
它工作正常。 但是在文本字段中插入數據后,它把我帶到另一個視圖,當我回到這個頁面時,它只是跳躍,我看不到我的文本字段。 這個問題有沒有更好的解決方案?
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[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 {
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
#pragma mark - keyboard movements
- (void)keyboardWillShow:(NSNotification *)notification
{
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
[UIView animateWithDuration:0.3 animations:^{
CGRect f = self.view.frame;
f.origin.y = -keyboardSize.height;
self.view.frame = f;
}];
}
-(void)keyboardWillHide:(NSNotification *)notification
{
[UIView animateWithDuration:0.3 animations:^{
CGRect f = self.view.frame;
f.origin.y = 0.0f;
self.view.frame = f;
}];
}
使用以下代碼來顯示和隱藏鍵盤
//Declare a delegate, assign your textField to the delegate and then include these methods
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];
return YES;
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil];
[self.view endEditing:YES];
return YES;
}
- (void)keyboardDidShow:(NSNotification *)notification
{
// Assign new frame to your view
[self.view setFrame:CGRectMake(0,-110,320,460)]; //here taken -110 for example i.e. your view will be scrolled to -110. change its value according to your requirement.
}
-(void)keyboardDidHide:(NSNotification *)notification
{
[self.view setFrame:CGRectMake(0,0,320,460)];
}
我在UIView
上寫了一個小類別,它可以管理臨時滾動的東西,而無需將整個東西包裝到UIScrollView
。 我在這里使用的動詞“滾動”可能並不理想,因為它可能會讓您認為涉及到滾動視圖,而實際上並沒有——我們只是在為UIView
(或UIView
子類)的位置設置動畫。
其中嵌入了一堆適合我的形式和布局的神奇數字,但可能不適合您的形式和布局,因此我鼓勵對其進行調整以滿足您的特定需求。
UIView+FormScroll.h:
#import <Foundation/Foundation.h>
@interface UIView (FormScroll)
-(void)scrollToY:(float)y;
-(void)scrollToView:(UIView *)view;
-(void)scrollElement:(UIView *)view toPoint:(float)y;
@end
UIView+FormScroll.m:
#import "UIView+FormScroll.h"
@implementation UIView (FormScroll)
-(void)scrollToY:(float)y
{
[UIView beginAnimations:@"registerScroll" context:NULL];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:0.4];
self.transform = CGAffineTransformMakeTranslation(0, y);
[UIView commitAnimations];
}
-(void)scrollToView:(UIView *)view
{
CGRect theFrame = view.frame;
float y = theFrame.origin.y - 15;
y -= (y/1.7);
[self scrollToY:-y];
}
-(void)scrollElement:(UIView *)view toPoint:(float)y
{
CGRect theFrame = view.frame;
float orig_y = theFrame.origin.y;
float diff = y - orig_y;
if (diff < 0) {
[self scrollToY:diff];
}
else {
[self scrollToY:0];
}
}
@end
將它導入你的 UIViewController,然后你就可以了
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
[self.view scrollToView:textField];
}
-(void) textFieldDidEndEditing:(UITextField *)textField
{
[self.view scrollToY:0];
[textField resignFirstResponder];
}
...管他呢。 該類別為您提供了三種非常好的調整視圖位置的方法。
將視圖綁定到鍵盤也是一個選項(請參閱答案底部的 GIF)
使用擴展:(未完全測試)
extension UIView{
func bindToKeyboard(){
NotificationCenter.default.addObserver(self, selector: #selector(UIView.keyboardWillChange(notification:)), name: Notification.Name.UIKeyboardWillChangeFrame, object: nil)
}
func unbindToKeyboard(){
NotificationCenter.default.removeObserver(self, name: Notification.Name.UIKeyboardWillChangeFrame, object: nil)
}
@objc
func keyboardWillChange(notification: Notification) {
let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt
let curFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
let targetFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
let deltaY = targetFrame.origin.y - curFrame.origin.y
UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: {
self.frame.origin.y+=deltaY
},completion: nil)
}
}
使用擴展名:
extension UIView{
func bindToKeyboard(){
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(UIView.keyboardWillChange(_:)), name: UIKeyboardWillChangeFrameNotification, object: nil)
}
func keyboardWillChange(notification: NSNotification) {
let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt
let curFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).CGRectValue()
let targetFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue()
let deltaY = targetFrame.origin.y - curFrame.origin.y
UIView.animateKeyframesWithDuration(duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: {
self.frame.origin.y+=deltaY
},completion: nil)
}
}
用法:
// view did load...
textField.bindToKeyboard()
...
// view unload
textField.unbindToKeyboard()
重要的
卸載視圖時不要忘記移除觀察者
我發現theDuncs 的回答非常有用,您可以在下面找到我自己的(重構)版本:
- (void)viewWillAppear:(BOOL)animated {
[[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:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
- (void)keyboardWillShow:(NSNotification *)notification {
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
float newVerticalPosition = -keyboardSize.height;
[self moveFrameToVerticalPosition:newVerticalPosition forDuration:0.3f];
}
- (void)keyboardWillHide:(NSNotification *)notification {
[self moveFrameToVerticalPosition:0.0f forDuration:0.3f];
}
- (void)moveFrameToVerticalPosition:(float)position forDuration:(float)duration {
CGRect frame = self.view.frame;
frame.origin.y = position;
[UIView animateWithDuration:duration animations:^{
self.view.frame = frame;
}];
}
基於 Daniel Krom 的解決方案。 這是swift 3.0 中的版本。 與AutoLayout配合使用效果很好,並在鍵盤出現時移動整個視圖。
extension UIView {
func bindToKeyboard(){
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange), name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil)
}
func unbindFromKeyboard(){
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil)
}
@objc
func keyboardWillChange(notification: NSNotification) {
guard let userInfo = notification.userInfo else { return }
let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as! Double
let curve = userInfo[UIKeyboardAnimationCurveUserInfoKey] as! UInt
let curFrame = (userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
let targetFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
let deltaY = targetFrame.origin.y - curFrame.origin.y
UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: {
self.frame.origin.y += deltaY
})
}
}
如何使用它:在viewDidLoad
添加bindToKeyboard
函數,如:
override func viewDidLoad() {
super.viewDidLoad()
view.bindToKeyboard()
}
並在 deinit 中添加unbindFromKeyboard
函數:
deinit {
view.unbindFromKeyboard()
}
上面 Daniel Krom 的更新版本的答案:
extension UIView {
func bindToKeyboard() {
NotificationCenter.default.addObserver(
self,
selector: #selector(UIView.keyboardWillChange(notification:)),
name: UIResponder.keyboardWillChangeFrameNotification,
object: nil
)
}
func unbindToKeyboard() {
NotificationCenter.default.removeObserver(
self,
name: UIResponder.keyboardWillChangeFrameNotification,
object: nil
)
}
@objc func keyboardWillChange(notification: Notification) {
let duration = notification.userInfo![UIResponder.keyboardAnimationDurationUserInfoKey] as! Double
let curve = notification.userInfo![UIResponder.keyboardAnimationCurveUserInfoKey] as! UInt
let curFrame = (notification.userInfo![UIResponder.keyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
let targetFrame = (notification.userInfo![UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
let deltaY = targetFrame.origin.y - curFrame.origin.y
UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIView.KeyframeAnimationOptions(rawValue: curve), animations: {
self.frame.origin.y += deltaY
})
}
}
對於與 KeyBoard 相關的所有問題,只需使用 IQKeyBoardManager 即可。 https://github.com/hackiftekhar/IQKeyboardManager 。
試試這個:-
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector (keyboardDidShow:)
name: UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector (keyboardDidHide:)
name: UIKeyboardDidHideNotification object:nil];
-(void) keyboardDidShow: (NSNotification *)notif
{
CGSize keyboardSize = [[[notif userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize.height+[self getTableView].tableFooterView.frame.size.height, 0.0);
[self getTableView].contentInset = contentInsets;
[self getTableView].scrollIndicatorInsets = contentInsets;
CGRect rect = self.frame; rect.size.height -= keyboardSize.height;
if (!CGRectContainsPoint(rect, self.frame.origin))
{
CGPoint scrollPoint = CGPointMake(0.0, self.frame.origin.y - (keyboardSize.height - self.frame.size.height));
[[self getTableView] setContentOffset:scrollPoint animated:YES];
}
}
-(void) keyboardDidHide: (NSNotification *)notif
{
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
[self getTableView].contentInset = contentInsets;
[self getTableView].scrollIndicatorInsets = contentInsets;
}
基於theDunc 的回答,但使用自動布局用 Swift 編寫。
@IBOutlet weak var bottomConstraint: NSLayoutConstraint! // connect the bottom of the view you want to move to the bottom layout guide
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
NSNotificationCenter.defaultCenter().addObserver(self,
selector: #selector(ConversationViewController.keyboardWillShow(_:)),
name: UIKeyboardWillShowNotification,
object: nil)
NSNotificationCenter.defaultCenter().addObserver(self,
selector: #selector(ConversationViewController.keyboardWillHide(_:)),
name: UIKeyboardWillHideNotification,
object: nil)
}
override func viewWillDisappear(animated: Bool) {
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
super.viewWillDisappear(animated)
}
// MARK: - Keyboard events
func keyboardWillShow(notification: NSNotification) {
if let userInfo = notification.userInfo,
keyboardFrame = userInfo[UIKeyboardFrameBeginUserInfoKey]
{
let keyboardSize = keyboardFrame.CGRectValue().size
self.bottomConstraint.constant = keyboardSize.height
UIView.animateWithDuration(0.3) {
self.view.layoutIfNeeded()
}
}
}
func keyboardWillHide(notification: NSNotification) {
self.bottomConstraint.constant = 0
UIView.animateWithDuration(0.3) {
self.view.layoutIfNeeded()
}
}
我已經實現了一個自定義控制器,它動態計算鍵盤的大小,在出現和消失時滾動 textFields,即使在設備旋轉期間也是如此。 適用於所有 iOS 設備。 只需簡單地繼承控制器即可擁有您需要的東西。 您可以在以下鏈接中找到所有說明: https : //github.com/mikthebig/ios-textfield-scroll
無需添加觀察者通知的簡單解決方案
-(void)setViewMovedUp:(BOOL)movedUp
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3]; // if you want to slide up the view
CGRect rect = self.view.frame;
if (movedUp)
{
// 1. move the view's origin up so that the text field that will be hidden come above the keyboard
// 2. increase the size of the view so that the area behind the keyboard is covered up.
rect.origin.y -= kOFFSET_FOR_KEYBOARD;
rect.size.height += kOFFSET_FOR_KEYBOARD;
}
else
{
// revert back to the normal state.
rect.origin.y += kOFFSET_FOR_KEYBOARD;
rect.size.height -= kOFFSET_FOR_KEYBOARD;
}
self.view.frame = rect;
[UIView commitAnimations];
}
-(void)textFieldDidEndEditing:(UITextField *)sender
{
if (self.view.frame.origin.y >= 0)
{
[self setViewMovedUp:NO];
}
}
-(void)textFieldDidBeginEditing:(UITextField *)sender
{
//move the main view, so that the keyboard does not hide it.
if (self.view.frame.origin.y >= 0)
{
[self setViewMovedUp:YES];
}
}
在哪里
#define kOFFSET_FOR_KEYBOARD 80.0
干得好。 不過,我已將此代碼與 UIView 一起使用。 您應該能夠對滾動視圖進行這些調整。
func addKeyboardNotifications() {
NotificationCenter.default.addObserver(self,
selector: #selector(keyboardWillShow(notification:)),
name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(keyboardWillHide(notification:)),
name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
// if using constraints
// bottomViewBottomSpaceConstraint.constant = keyboardSize.height
self.view.frame.origin.y -= keyboardSize.height
UIView.animate(withDuration: duration) {
self.view.layoutIfNeeded()
}
}
}
func keyboardWillHide(notification: NSNotification) {
let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
//if using constraint
// bottomViewBottomSpaceConstraint.constant = 0
self.view.frame.origin.y = 0
UIView.animate(withDuration: duration) {
self.view.layoutIfNeeded()
}
}
不要忘記在正確的位置刪除通知。
func removeKeyboardNotifications() {
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
斯威夫特 4
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange), name: .UIKeyboardWillChangeFrame, object: nil)
@objc func keyboardWillChange(notification: NSNotification) {
let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt
let curFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
let targetFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
let deltaY = targetFrame.origin.y - curFrame.origin.y
UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: {
self.YourView.frame.origin.y+=deltaY
},completion: nil)
}
以防萬一有人在Swift 中尋找解決方案,請將其放入您的代碼中:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: .UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: .UIKeyboardWillHide, object: nil)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: nil)
}
@objc func keyboardWillShow(notification: Notification) {
if let userInfo = notification.userInfo {
if let keyboardSize = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
UIView.animate(withDuration: 0.3) {
var alteredFrame = self.view.frame
alteredFrame.origin.y = -keyboardSize.height
self.view.frame = alteredFrame
}
}
}
}
@objc func keyboardWillHide(notification: Notification) {
UIView.animate(withDuration: 0.3) {
var alteredFrame = self.view.frame
alteredFrame.origin.y = 0.0
self.view.frame = alteredFrame
}
}
如果該textfield
位於表格的單元格中(即使table.scrollable = NO
),也可以輕松自動textfield
。
注意:桌子的位置和大小必須合理。 例如:
height = 10
,並且當鍵盤出現時其中的textfield
必須向上滾動 100 才能可見,那么該文本字段將超出表的范圍。聲明一個委托,將您的文本字段分配給該委托,然后包含這些方法。
假設您有一個帶有電子郵件和密碼文本字段的登錄表單,此代碼將非常適合:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self.emailTextField resignFirstResponder];
[self.passwordTextField resignFirstResponder];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
if (self.emailTextField == textField) {
[self.passwordTextField becomeFirstResponder];
} else {
[self.emailTextField resignFirstResponder];
[self.passwordTextField resignFirstResponder];
}
return NO;
}
- (void)viewWillAppear:(BOOL)animated {
[[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:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
#pragma mark - keyboard movements
- (void)keyboardWillShow:(NSNotification *)notification
{
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
[UIView animateWithDuration:0.3 animations:^{
CGRect f = self.view.frame;
f.origin.y = -0.5f * keyboardSize.height;
self.view.frame = f;
}];
}
-(void)keyboardWillHide:(NSNotification *)notification
{
[UIView animateWithDuration:0.3 animations:^{
CGRect f = self.view.frame;
f.origin.y = 0.0f;
self.view.frame = f;
}];
}
我剛剛創建了一個輕量級的鍵盤處理程序來跟隨鍵盤框架。
用法:
self.keyboardHandler = [EDKeyboardHandler new];
[self.keyboardHandler listenWithBlock:^(KeyboardInfo *model)
{
//adjust view positions according to keyboard position here
}];
並且 KeyboardInfo 模型具有以下屬性:
typedef enum : NSUInteger {
KeyboardStatusDidShow,
KeyboardStatusWillShow,
KeyboardStatusDidHide,
KeyboardStatusWillHide,
} KeyboardStatus;
@interface KeyboardInfo:NSObject
@property (nonatomic,readonly) NSTimeInterval animationDuration;
@property (nonatomic,readonly) CGRect keyboardFrame;
@property (nonatomic,readonly) NSInteger animationCurve;
@property (nonatomic,readonly) KeyboardStatus status;
@end
查看GitHub項目了解詳細信息和 cocoaPods 集成。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.