#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