幾行代碼搞定UITextField彈起鍵盤遮擋視圖問題

先看效果圖


先看效果圖

問題描述

在開發(fā)中經(jīng)常會遇到點擊輸入框激活鍵盤的時候,彈出的鍵盤導致輸入框被遮擋的現(xiàn)象。常用的解決方案有兩種:
1.鍵盤彈出的時候,將整個視圖上移。
2.鍵盤彈出的時候,懸浮輸入框到適當位置。

第一種方案比較簡單,常用的實現(xiàn)方式有三種:

  • 給UITextField注冊監(jiān)聽事件:UIControlEventEditingDidBeginUIControlEventEditingDidEnd
  • 協(xié)議+代理:通過UITextField的代理方法來實現(xiàn)
  • 用通知來實現(xiàn)

幾種方式分析

  • 方法1:如果給UITextField注冊監(jiān)聽事件,監(jiān)聽正在編輯和編輯完畢,需要自己寫一個正在編輯和編輯完畢時候視圖位置改變的方法,如果有多個UITextField,那么每個都要添加監(jiān)聽事件,很麻煩。

    UITextField * usernameTextField = [[UITextField alloc]initWithFrame:CGRectMake(30, 30, 100, 30)];
//    UITextField * passwordTextField = [[UITextField alloc]initWithFrame:CGRectMake(30, 160, 100, 30)];
    
    // 添加監(jiān)聽事件
    // 開始輸入
    [usernameTextField addTarget:self action:@selector(textFieldEditBegin) forControlEvents:UIControlEventEditingDidBegin];
    // 輸入結(jié)束
    [usernameTextField addTarget:self action:@selector(textFieldEditEnd) forControlEvents:UIControlEventEditingDidEnd];
    
    [self.view addSubview:usernameTextField];
  • 方法二:通過UITextField的代理方法進行設(shè)置,代理方法有:
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField; // 文本框是否可以編輯

- (void)textFieldDidBeginEditing:(UITextField *)textField;   // 開始編輯時調(diào)用

- (BOOL)textFieldShouldEndEditing:(UITextField *)textField;   // 文本是否結(jié)束編輯

- (void)textFieldDidEndEditing:(UITextField *)textField;     // 結(jié)束編輯時調(diào)用

- (BOOL)textFieldShouldClear:(UITextField *)textField;        // 是否可以清楚文本框的內(nèi)容

- (BOOL)textFieldShouldReturn:(UITextField *)textField;      // 是否可以return
  • 在代理方法textFieldDidBeginEditingtextFieldDidEndEditing里面實現(xiàn)視圖的偏移

  • 方法3:用UITextField的通知UIKeyboardWillChangeFrameNotification來實現(xiàn),只需要在監(jiān)聽通知,設(shè)置視圖偏移的動畫

所以采用通知的形式來實現(xiàn)

完整代碼(重要)

#import "ViewController.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UITextField *usernameTextField;
@property (weak, nonatomic) IBOutlet UITextField *passwordTextField;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // 監(jiān)聽通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil]; 
}

#pragma mark 鍵盤處理
- (void)keyboardWillChangeFrame:(NSNotification *)note{
    // 取出鍵盤最終的frame
    CGRect rect = [note.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
    // 取出鍵盤彈出需要花費的時間
    double duration = [note.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    // 修改transform
    [UIView animateWithDuration:duration animations:^{
        CGFloat ty = [UIScreen mainScreen].bounds.size.height - rect.origin.y;
        self.view.transform = CGAffineTransformMakeTranslation(0, - ty);
    }];
}
/**
 * 點擊屏幕的時候
 */
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [self.view endEditing:YES];
    
}
-(void)dealloc{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

補充 - 關(guān)于通知

通知中心(NSNotificationCenter)

  • 每一個應(yīng)用程序都有一個通知中心(NSNotificationCenter)實例,專門負責協(xié)助不同對象之間的消息通信。
  • 任何一個對象都可以向通知中心發(fā)布通知(NSNotification),描述自己在在做什么。
  • 其他感興趣的對象(Observer)可以申請在某個特定通知發(fā)布時(或在某個特定的對象發(fā)布通知的時候)收到這個通知。
    NSNotificationCenter

通知(NSNotificationCenter)

  • 通知包含的屬性:
    • 通知名稱;
    • 通知發(fā)布者;
    • /額外信息(通知發(fā)布者傳遞給通知接收著的信息內(nèi)容).
    - (NSString *)name;  // 通知名稱
    - (id)object;   // 通知發(fā)布者
    - (NSDictionary *)userInfo; //額外信息(通知發(fā)布者傳遞給通知接收著的信息內(nèi)容)
  • 初始化通知對象的方法:
+ (instancetype)notificationWithName:(NSNotificationName)aName object:(nullable id)anObject;
+ (instancetype)notificationWithName:(NSNotificationName)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo;

- (instancetype)init

發(fā)布通知

- (void)postNotification:(NSNotification *)notification;

發(fā)布一個notification通知,可在notification對象中設(shè)置通知的名稱、通知發(fā)布者、額外信息等

- (void)postNotificationName:(NSNotificationName)aName object:(nullable id)anObject;

發(fā)布一個名稱為aName的通知,anObject為這個通知的發(fā)布者

- (void)postNotificationName:(NSNotificationName)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo;

發(fā)布一個名稱為aName的通知,anObject為這個通知的發(fā)布者,aUserInfo為額外信息

監(jiān)聽通知

  • 通知中心提供了方法來注冊一個監(jiān)聽通知的監(jiān)聽器(Observer)
- (void)addObserver:(id)observer selector:(SEL)aSelector name:(nullable NSNotificationName)aName object:(nullable id)anObject;

observer:監(jiān)聽器
aSelector:接收通知后,回調(diào)監(jiān)聽器的這個放啊,并且把通知對象當參數(shù)傳入
aName:通知名稱。如果為nil,那么無論通知名稱是什么,監(jiān)聽器都能收到這個通知
anObject:通知發(fā)布者。如果anObjectaName都為nil,監(jiān)聽器都能收到所有通知

- (id <NSObject>)addObserverForName:(nullable NSNotificationName)name object:(nullable id)obj queue:(nullable NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block ;

name:通知名稱
obj:通知發(fā)布者
block:收到對應(yīng)的通知時,會回調(diào)這個block
queue:決定了block在哪個操作隊列中執(zhí)行,如果為nil,默認在當前操作隊列中同步執(zhí)行。

取消注冊通知監(jiān)聽器

通知中心不會保留(retain)監(jiān)聽器對象,在通知中心注冊過的對象,必須在該對象釋放前取消注冊。否則,當相應(yīng)的通知再次出現(xiàn)時,通知中心仍然會想該監(jiān)聽器發(fā)送消息。因為相應(yīng)的監(jiān)聽器對象已經(jīng)釋放了,所以可能會導致應(yīng)用崩潰。

  • 通知中心提供了相應(yīng)的方法來取消注冊注冊監(jiān)聽器
- (void)removeObserver:(id)observer;
- (void)removeObserver:(id)observer name:(nullable NSNotificationName)aName object:(nullable id)anObject;

鍵盤通知

  • UIKeyboardWillShowNotification:鍵盤即將顯示
  • UIKeyboardDidShowNotification:鍵盤已經(jīng)顯示完畢
  • UIKeyboardWillHideNotification:鍵盤即將隱藏
  • UIKeyboardDidHideNotification:鍵盤已經(jīng)隱藏完畢
  • UIKeyboardWillChangeFrameNotification:鍵盤的位置尺寸即將發(fā)生改變
  • UIKeyboardDidChangeFrameNotification:鍵盤的位置尺寸已經(jīng)發(fā)生改變
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容