#import "ViewController.h"
@interface ViewController ()<UITextFieldDelegate>
@property (nonatomic, strong) UIView * containerView;//背景View
@property (nonatomic, assign) CGFloat originalY;//原始縱座標
@property (nonatomic, assign) CGFloat containerViewHeight;//原始高度
@property (nonatomic, strong) UITextField * account;//賬號輸入框
@property (nonatomic, strong) UITextField * password;//密碼輸入框
@property (nonatomic, strong) UIButton * commitButton;//提交按鈕
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self creatBgView];
[self createOneAccountView];
[self createOnePasswordView];
[self createOneButton];
[self registerKeyboardNotification];
}
#pragma mark - 創建一個背景View
-(void)creatBgView{
UIView * containerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 280, 300)];
self.containerView = containerView;
containerView.backgroundColor = [UIColor darkGrayColor];
containerView.center = self.view.center;
[self.view addSubview:containerView];
//記錄下container的原始縱座標和高度 這一步很關鍵後面後用到這裏的數據
CGFloat originalY = self.containerView.frame.origin.y;
self.originalY = originalY;
CGFloat containerViewHeight = self.containerView.frame.size.height;
self.containerViewHeight = containerViewHeight;
}
#pragma mark - 創建一個賬號輸入框
-(void)createOneAccountView{
UITextField * account = [[UITextField alloc] initWithFrame:CGRectMake(40, 80, 200, 40)];
self.account = account;
self.account.delegate = self;
//一、顯示相關設置
//1、背景顏色設置
account.backgroundColor = [UIColor redColor];
//2、背景圖片設置
account.background = [UIImage imageNamed:@""];
/*
3、邊框樣式設置
UITextBorderStyleNone, //無邊框效果
UITextBorderStyleLine, //黑色實線邊框
UITextBorderStyleBezel, //灰色實線邊框
UITextBorderStyleRoundedRect //圓角矩形邊框
*/
account.borderStyle = UITextBorderStyleRoundedRect;
//4、左側頭視圖設置
//左側頭試圖 x y值無效果
UIView *leftView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 10, 40)];
//clearColor 將衍射設爲透明顏色 可用來調節光標的位置
leftView.backgroundColor = [UIColor blueColor];
//設置什麼時候顯示
account.leftViewMode = UITextFieldViewModeAlways;
account.leftView = leftView;
//5、右側頭視圖設置
//右側頭視圖 x y值無效果
UIView *rightView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 10, 40)];
//設置顏色
rightView.backgroundColor = [UIColor blueColor];
//設置什麼時候顯示
account.rightViewMode = UITextFieldViewModeAlways;
account.rightView = rightView;
//二、文字設置
//1、佔位文字設置
account.placeholder = @"請輸入賬號";
//2、內容設置,比如設置自動填充。
account.text = @"內容設置";
//3、內容是否以密文形式顯示
// account.secureTextEntry = YES;
//4、重新編輯時是否自動清除內容
account.clearsOnBeginEditing = YES;
/*
5、刪除按鈕顯示設置
UITextFieldViewModeNever, //清除按鈕不可見
UITextFieldViewModeWhileEditing, //編輯內容時清除按鈕可見
UITextFieldViewModeUnlessEditing, //除了編輯之外,清除按鈕都可見
UITextFieldViewModeAlways //清除按鈕一直可見
*/
//疑問1:UITextFieldViewModeUnlessEditing爲什麼設置這個沒有效果
account.clearButtonMode = UITextFieldViewModeWhileEditing;
//6、這兩個屬性配合使用,一個用來設置字體自動適應,一個用來設置允許最小的字體
account.adjustsFontSizeToFitWidth = YES;
account.minimumFontSize = 10;
/*
7、字母大小寫自動轉換
UITextAutocapitalizationTypeNone, //無自動轉換
UITextAutocapitalizationTypeWords, //首字母自動轉大寫
UITextAutocapitalizationTypeSentences, //每個句子的首字母轉大寫
UITextAutocapitalizationTypeAllCharacters, //所有字母自動轉大寫
*/
account.autocapitalizationType = UITextAutocapitalizationTypeSentences;
/*
8、輸入文字時自動更正提示框
UITextAutocorrectionTypeDefault,
UITextAutocorrectionTypeNo,
UITextAutocorrectionTypeYes,
*/
account.autocorrectionType = UITextAutocorrectionTypeDefault;
//9、響應者問題 成爲第一響應者 程序進來的時候,光標會在這個輸入框內閃爍,也就是已經來到了DidBeginEditing狀態
//設置了代理的話,這個方法會使程序調用 1、2、這兩個代理方法
// [account becomeFirstResponder];
//10、註銷第一響應者會結束編輯
//這個方法會使輸入框結束編輯,設置了代理的話,這個方法會使程序調用4、5、這個兩個代理方法
//一般在點擊return鍵的時候會調用這個方法來結束輸入框的編輯狀態
// [account resignFirstResponder];
//三、鍵盤設置相關
//1、設置不同的鍵盤類型
account.keyboardType = UIKeyboardTypeNumbersAndPunctuation;
//2、返回鍵的樣式
account.returnKeyType = UIReturnKeyGo;
//設爲yes時 只有當輸入內容時return鍵纔可用
//設爲no時,什麼時候都可用,不會鎖定
// account.enablesReturnKeyAutomatically = YES;
//3、鍵盤顯示樣式
account.keyboardAppearance = UIKeyboardAppearanceDark;
//4、自定義鍵盤
UIView *keyView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 320, 100)];
keyView.backgroundColor = [UIColor redColor];
account.inputView = keyView;
//5、自定義二級鍵盤
UIView *secondView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 320, 40)];
secondView.backgroundColor = [UIColor greenColor];
// account.inputAccessoryView = secondView;
[self.containerView addSubview:account];
}
#pragma mark - 創建一個密碼輸入框
-(void)createOnePasswordView{
UITextField * password = [[UITextField alloc] initWithFrame:CGRectMake(40, 140, 200, 40)];
self.password = password;
self.password.delegate = self;
password.backgroundColor = [UIColor lightGrayColor];
password.placeholder = @"請輸入密碼";
password.returnKeyType = UIReturnKeyNext;
[self.containerView addSubview:password];
}
#pragma mark - 創建一個提交按鈕
-(void)createOneButton{
UIButton * commit = [UIButton buttonWithType:UIButtonTypeCustom];
commit.frame = CGRectMake(90, self.containerView.frame.size.height-100, 100, 40);
self.commitButton = commit;
[commit setTitle:@"提交" forState:UIControlStateNormal];
commit.backgroundColor = [UIColor redColor];
[self.containerView addSubview:commit];
}
#pragma mark - 註冊鍵盤通知
-(void)registerKeyboardNotification{
//1、鍵盤將要顯示
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
//2、鍵盤顯示完成
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];
//3、鍵盤將要隱藏
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
//4、鍵盤隱藏完成
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil];
//5、鍵盤的frame將要變化的通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];
//6、鍵盤的frame變化完成的通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidChangeFrame:) name:UIKeyboardDidChangeFrameNotification object:nil];
}
-(void)keyboardWillShow:(NSNotification *)notification{
//1、鍵盤將要彈出時調用此方法
NSDictionary * userInfo = notification.userInfo;
// NSLog(@"willShowUserInfo = %@",userInfo);
//通知中各個參數說明
/*
UIKeyboardAnimationCurveUserInfoKey = 7; //動畫樣式
UIKeyboardAnimationDurationUserInfoKey = "0.25"; //動畫時間
UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {375, 258}}"; //鍵盤的bounds
UIKeyboardCenterBeginUserInfoKey = "NSPoint: {187.5, 796}"; //鍵盤變化開始時的center
UIKeyboardCenterEndUserInfoKey = "NSPoint: {187.5, 538}"; //鍵盤變化結束時的center
UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 667}, {375, 258}}"; //鍵盤變化開始時的frame
UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 409}, {375, 258}}"; //鍵盤變化結束時的frame
UIKeyboardIsLocalUserInfoKey = 1; //ipad多任務同時運行,所有運行可見的app都會收到鍵盤通知,調出鍵盤的app返回的是1,其它app返回的是0
*/
//解決鍵盤彈出覆蓋其它視圖的問題
//鍵盤高度
CGRect keyBoardFrame = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGFloat keyBoardY = keyBoardFrame.origin.y; //鍵盤y座標
//計算平移距離translationY 這裏一定要跟container的原始位置尺寸進行比較來計算 否則在兩個textFieldView之間進行切換時可能出現問題
//大於0 證明有間隙
//等於0 證明剛剛好
//小於0 證明有覆蓋
CGFloat translationY = keyBoardY - (self.originalY + self.containerViewHeight);
NSLog(@"translatinY = %lf",translationY);
#if 0
//只在被覆蓋的情況下才進行平移操作
if (translationY < 0) {
self.containerView.transform = CGAffineTransformMakeTranslation(0, translationY);
}
else{
//else這部分代碼是不可少的 舉個例子:
//1、第一次鍵盤彈出view被遮擋,view就會根據translationY進行平移
//2、第二次鍵盤彈出時view沒被遮擋,view就需要回到原始位置,而不是待在平移後的位置
//這種情況會出現在 在兩個或多個textFieldView之間切換時
self.containerView.transform = CGAffineTransformIdentity;
}
#elif 0
//根據鍵盤的高度進行平移
if (translationY < 0) {
//鍵盤彈出被覆蓋 上移
self.containerView.transform = CGAffineTransformMakeTranslation(0, translationY);
}
else if(translationY == 0){
//剛剛好 就復原到原來位置 同上這部分是不可少的
#if 0
self.containerView.transform = CGAffineTransformMakeTranslation(0, 0);
#else
self.containerView.transform = CGAffineTransformIdentity;
#endif
}
else{
//與鍵盤有間隔 下移
self.containerView.transform = CGAffineTransformMakeTranslation(0, translationY);
}
#elif 0
//其實上邊的代碼完全可以這麼寫就OK 這裏的關鍵是記錄下containerView最原始的位置信息
self.containerView.transform = CGAffineTransformMakeTranslation(0, translationY);
#elif 1
//通過這種方法也可以達到緊貼鍵盤的目的 而不用記錄原始位置信息
CGFloat changeY = self.containerView.frame.origin.y; //view的實時Y座標
CGFloat conHeight = self.containerView.frame.size.height; //view的高度
CGFloat keyY = keyBoardFrame.origin.y; //鍵盤Y座標
CGFloat changeTranslationY = keyY- (changeY + conHeight);
self.containerView.transform = CGAffineTransformTranslate(self.containerView.transform , 0,changeTranslationY);
#endif
/*********************************************************************************************************\
* PS:重要說明
* 當在多個textField 之間切換時
* 點擊第一個textField鍵盤彈出,此時再去點另外一個textFieldView,鍵盤是不會隱藏後再彈出的,而是一直保持彈出狀態。
* 這個過程中textField的通知方法調用也不會來到keyboardWillHide方法,但會來到keyboardWillShow方法
*
*
\*********************************************************************************************************/
}
-(void)keyboardDidShow:(NSNotification *)notification{
//2、鍵盤彈出完成時調用此方法
NSDictionary * userInfo = notification.userInfo;
// NSLog(@"didShowUserInfo = %@",userInfo);
/*
UIKeyboardAnimationCurveUserInfoKey = 7;
UIKeyboardAnimationDurationUserInfoKey = "0.25";
UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {375, 258}}";
UIKeyboardCenterBeginUserInfoKey = "NSPoint: {187.5, 796}";
UIKeyboardCenterEndUserInfoKey = "NSPoint: {187.5, 538}";
UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 667}, {375, 258}}";
UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 409}, {375, 258}}";
UIKeyboardIsLocalUserInfoKey = 1;
*/
}
-(void)keyboardWillHide:(NSNotification *)notification{
//3、鍵盤將要隱藏式調用此方法
NSDictionary * userInfo = notification.userInfo;
// NSLog(@"willHideUserInfo = %@",userInfo);
/*
UIKeyboardAnimationCurveUserInfoKey = 7;
UIKeyboardAnimationDurationUserInfoKey = "0.25";
UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {375, 258}}";
UIKeyboardCenterBeginUserInfoKey = "NSPoint: {187.5, 538}";
UIKeyboardCenterEndUserInfoKey = "NSPoint: {187.5, 796}";
UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 409}, {375, 258}}";
UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 667}, {375, 258}}";
UIKeyboardIsLocalUserInfoKey = 1;
*/
self.containerView.transform = CGAffineTransformIdentity;
}
-(void)keyboardDidHide:(NSNotification *)notification{
//4、鍵盤隱藏完成時調用此方法
NSDictionary * userInfo = notification.userInfo;
// NSLog(@"didHideUserInfo = %@",userInfo);
/*
UIKeyboardAnimationCurveUserInfoKey = 7;
UIKeyboardAnimationDurationUserInfoKey = "0.25";
UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {375, 258}}";
UIKeyboardCenterBeginUserInfoKey = "NSPoint: {187.5, 538}";
UIKeyboardCenterEndUserInfoKey = "NSPoint: {187.5, 796}";
UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 409}, {375, 258}}";
UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 667}, {375, 258}}";
UIKeyboardIsLocalUserInfoKey = 1;
*/
}
-(void)keyboardWillChangeFrame:(NSNotification *)notification{
//5、只要鍵盤的frame發生變化就會來到此方法
}
-(void)keyboardDidChangeFrame:(NSNotification *)notification{
//6、鍵盤的frame變化完成就會來都此方法
}
/*********************************************************************************************************\
* PS:重要說明
* 鍵盤從彈出到隱藏的執行順序爲:
* 5-1-6-2-5-3-6-4
*
*
*
\**********************************************************************************************************/
#pragma mark - UITextFieldDelegate
//1、是否允許編輯 yes爲允許 no爲否
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
NSLog(@"是否可以開始編輯");
return YES;
}
//2、已經開始編輯 開始編輯的時候會調用一次
- (void)textFieldDidBeginEditing:(UITextField *)textField{
NSLog(@"已經開始編輯");
}
//3、是否允許改變內容
//yes當輸入時輸入框內容隨輸入改變 no不會改變
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
//range.location返回的是輸入或刪除的字符所在的index
//range.length 一個一個輸入時返回的總是0 一個一個刪除時返回的總是1 用來判斷是刪除還是輸入?
//當剪切輸入框的內容時range.length 是剪切走的字符個數
NSLog(@"range.location = %lu ,range.length = %lu",range.location,(unsigned long)range.length);
//輸入或刪除的字符
NSLog(@"string = %@",string);
return YES;
}
//4、是否能結束編輯 yes爲允許 no爲否
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField{
NSLog(@"是否允許結束編輯");
return YES;
}
//5、已經結束編輯
- (void)textFieldDidEndEditing:(UITextField *)textField{
NSLog(@"已經結束編輯");
}
/**
* PS
當只有一個textfield時,從點擊-編輯-離開的執行順序爲1、2、3、4、5
如果是在兩個textfield之間切換,代理執行的順序是:
點擊第一個testField:1、2、3、 編輯完成
再點擊第二個testField:1、4、5、2、3、4、5
*
*/
//6、是否允許清除 比如點擊刪除按鈕 或者設置了自動清除 就會來到此方法
//yes就會清除輸入框的內容,no不會清除
- (BOOL)textFieldShouldClear:(UITextField *)textField{
return YES;
}
//7、點擊鍵盤右下角鍵來到此方法
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
//取消第一響應者 收起鍵盤
[textField resignFirstResponder];
//疑問2:這裏返回yes跟no有什麼區別
return YES;
}
//觸摸屏幕時調用
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
#if 1
//註銷第一響應者 鍵盤會隱藏
[self.account resignFirstResponder];
[self.password resignFirstResponder];
#else
//結束編輯鍵盤會隱藏
[self.view endEditing:YES];
#endif
}
//最後不要忘記移除監聽者
-(void)dealloc{
#if 0
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardDidShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardWillHideNotification
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardDidHideNotification
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardWillChangeFrameNotification
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardDidChangeFrameNotification
object:nil];
#else
[[NSNotificationCenter defaultCenter] removeObserver:self];
#endif
}
@end
參考文章:
1、ios 監聽系統鍵盤的出現和消失-布布扣-bubuko.com