iOS开发-------自定义简单的表情键盘(UICollectionView 集合视图)
2015-10-04 15:24
501 查看
最近制作自制表情键盘的时候,突然了解到还有一个叫做UICollectionView (集合视图)的类,就研究了一下,确实在做表情键盘上要比用 UIScrollView(滚动视图) 要简单的多,用法与 UITableView(表格视图) 相似,但楼主觉得稍微麻烦那么一点点,就是因为它必须要自顶一个cell,这个cell的类型是UICollectionViewCell,用到的仅仅是初级的用法,高级用法也请查看其他资料。
这一次按照自己的理解,用了一下自认为的MVC架构模式,如理解不妥,特请指正,话不多说,首先看一我的工程目录吧
接着看一下运行的结果吧,因为加了约束,所以横屏竖屏都是可以的
其实一般情况下,打印的表情发送到服务器的形式就是文本中的形式,以[ ]作为标识符,如果想在文本框中打出表情也是可以的,可以去看一下之前的一篇博客 iOS学习-------文字表情(NSAttributeString
属性字符串 以及 NSRegularExpression 正则表达类)
因为表情是通过本地的plist文件来读取的,所以首先看一下plist文件
整体是一个数组,每个数组元素都是一个字典,那么看到字典,首先想到的就是模型了
模型类很简单,只需要在实现.m文件中,实现 便利初始化方法 以及 便利构造器 即可,如果对便利初始化方法以及便利构造器不熟悉,也欢迎去之前的博客Objective-C学习- 便利初始化函数和便利构造器去复习一下。实现方法如下
首先实现便利初始化方法
目前只见过3种 '+' 方法,便利构造器,单例以及纯过程封装,下面便是便利构造器
因为不是很过复杂,所以没有写Manager(管理者),一般情况下,Manager是一个单例。
创建的基类(BaseCollectionViewCell)如下
实现方法木有,因为实现几乎没有意义
接着就是自定义的表情cell了,思路就是在cell上放置一个 button ,让 button 的 frame 大小等于 cell 的bounds,当点击的时候,通过回调返回点击按钮的表情以及文字标识符。但是返回的属性UIImage 和 imageName 是不能被修改的,所以属性上用的 readOnly,头文件如下
因为继承了BaseCollectionViewCell,所以在基类中没有实现的方法需要在EmoticonCell类中进行实现,首先实现基类中的两个方法
在setInfomationWithEmoticon:方法中用到了一个自定义的设置的方法,是之前写的,又不想删除,所以就起到了一个简化代码的作用,很简单的实现,如下
因为Cell的基类说到底就是UIView,所以必须要重写两个创建方法,如下
因为cellInit是自定义的创建方式,自然每个创建方法都要用,所以楼主打包成一个方法,偷个懒0.0
当button被点击的时候,之前的回调就有用了
这样自定义的Cell类就完成了。
首先因为他不是最后的boss(ViewController),所以也是需要汇报的,自然是少不了回调的,因为用Block回调比较多,所以依旧选择用Block回调,下面是声明文件.h中的声明:
接着就是在延展中,加入三个属性对象,分别用来显示表情(collectionView),存储表情的信息(emoticons),以及回调的方法Block(b),但是有一点不同,要用UICollectionView,要遵守三个协议,不是UITableView的两个协议,因为多了一个类似布局的协议,如下
因为是view,所以重写的那两个方法不再赘余,只说明自写的init方法
先从最简单的开始,加载数组,思路是先从plist文件中加载数据,然后通过遍历出的字典,通过字典转模型,再返回处理好的数组,如下
因为没有storyboard直接用UICollectionViewController,所以要结合自定义cell,只能通过在init中进行注册,为什么要单独出一个方法呢,不就是一句话么,如果cell足够多的话,只需要改动这个方法即可,不需要改动init方法。
倒数第二麻烦的就应该是布局了,虽然代码看起来很爽,但是确实是说,用stroyboard来布局是非常高效的,但楼主用的是代码。需要注意的就是一点,必须先添加到父视图上才可以进行布局,不然会出很多麻烦
最麻烦的就是数UICollectionView了,因为它有着各种协议以及各种配置问题,因为有注释,所以很明确,看一下配置方法
首先实现集合视图的数据源方法,首先看两个,很好理解,和UITableView简直就是双胞胎,只不过tableView用row,而CollectionView用item
接着就是实现自定义cell的方法,与UItableView稍有不同,但也是很好理解的
因为UICollectionViewDelegate的方法没有用到的,所以没有写相关方法,直接用的UICollectionViewDelegateFlowLayout方法,更多方法也可以按住option点击进入开发文档进行查看,方法如下
显示的view完毕
声明文件中只需要声明一个可查看键盘状态的属性,一个切换键盘的方法和具体改变键盘的方法即可
在延展中只需要一个表情视图(EmoticonsView)即可
自定义的init方法
实现切换键盘的两个方法即可
切换键盘的方法如下
改变键盘的方法如下
首先在延展中声明一个切换键盘的 按钮(UIButton) 以及 自定义的文本域(MyTextField) 即可
viewDidLoad上,楼主依旧用的是方法进行
首先加载button,用storyboard是很简单,因为用的是代码,所以看起来比较复杂,不做过多的解释,相信都能看得懂
接着是button的适配
按钮配置完毕后,就需要适配文本域了,加载方法如下
为文本域添加约束
切换按钮的回调方法,因为之前的铺垫,依旧很简单
基本的功能到此结束。
但是这样完善有一个不舒服的地方,就是输入完毕东西之后,键盘不能自动消失,但是重新加一个按钮又显得很low,所以楼主用的是一个轻击手势,怎么用呢,在延展中加入一个属性
在viewDidLoad中加入这个方法
配制方法
轻击后的回调方法
这样,双击后键盘就自动撤掉了。更多手势识别可以去看看之前的博客iOS学习-------手势识别,3Q
这一次按照自己的理解,用了一下自认为的MVC架构模式,如理解不妥,特请指正,话不多说,首先看一我的工程目录吧
接着看一下运行的结果吧,因为加了约束,所以横屏竖屏都是可以的
其实一般情况下,打印的表情发送到服务器的形式就是文本中的形式,以[ ]作为标识符,如果想在文本框中打出表情也是可以的,可以去看一下之前的一篇博客 iOS学习-------文字表情(NSAttributeString
属性字符串 以及 NSRegularExpression 正则表达类)
因为表情是通过本地的plist文件来读取的,所以首先看一下plist文件
整体是一个数组,每个数组元素都是一个字典,那么看到字典,首先想到的就是模型了
Model(模型)
首先创建一个表情类,即Emoticon类,存取数据的,以后的操作就是对表情(Emoticon)类的操作,而不是对字典的操作,首先是头文件// // Emoticon.h // 表情键盘 // // Created by YueWen on 15/10/3. // Copyright (c) 2015年 YueWen. All rights reserved. // #import <UIKit/UIKit.h> @interface Emoticon : NSObject /** * 繁体的汉字 */ @property(nonatomic,strong)NSString * cht; /** * 动态图名 */ @property(nonatomic,strong)NSString * gif; /** * 种类 */ @property(nonatomic,strong)NSNumber * type; /** * 简体的汉字 */ @property(nonatomic,strong)NSString * chs; /** * 静态图名 */ @property(nonatomic,strong)NSString * png; /** * 自定义初始化方法 * * @param dict 含参字典 * * @return 返回创建好的Emoticon对象 */ -(instancetype)initWithDictionary:(NSDictionary *)dict; /** * 便利构造器 * * @param dict 含参字典 * * @return 返回创建好的Emoticon对象 */ +(instancetype)emoticonWithDictionary:(NSDictionary *)dict; @end
模型类很简单,只需要在实现.m文件中,实现 便利初始化方法 以及 便利构造器 即可,如果对便利初始化方法以及便利构造器不熟悉,也欢迎去之前的博客Objective-C学习- 便利初始化函数和便利构造器去复习一下。实现方法如下
首先实现便利初始化方法
- (instancetype)initWithDictionary:(NSDictionary *)dict { self = [super init]; if (self) { //通过MVC进行赋值 [self setValuesForKeysWithDictionary:dict]; } return self; }
目前只见过3种 '+' 方法,便利构造器,单例以及纯过程封装,下面便是便利构造器
+(instancetype)emoticonWithDictionary:(NSDictionary *)dict { __autoreleasing Emoticon * emoticon = [[Emoticon alloc]initWithDictionary:dict]; return emoticon; }
因为不是很过复杂,所以没有写Manager(管理者),一般情况下,Manager是一个单例。
View (视图)
自定义的UICollectionViewCell
因为在UICollectionView(集合视图)中,没有默认的Cell,这点不像是UITableViewCell,因为没有用storyBoard拖东西,所以用的纯代码进行的布局,首先创建了一个叫做BaseCollectionViewCell (Cell 基类) ,为了以后好拓展,虽然看起来在做这个的时候会麻烦点。创建的基类(BaseCollectionViewCell)如下
#import <UIKit/UIKit.h> #import "Emoticon.h" typedef void(^emoticonButtonClickBlock)(UIImage * buttonImage,NSString * imageName); @interface BaseCollectionViewCell : UICollectionViewCell /** * 根据表情模型赋值 * * @param emoticon 表情模型 */ -(void)setInformationWithEmoticon:(Emoticon *)emoticon; /** * 设置block回调 * * @param emoticonButtonBlock 回调的代码块 */ -(void)emotionButtonClickBlockHandle:(emoticonButtonClickBlock)emoticonButtonBlock; @end
实现方法木有,因为实现几乎没有意义
接着就是自定义的表情cell了,思路就是在cell上放置一个 button ,让 button 的 frame 大小等于 cell 的bounds,当点击的时候,通过回调返回点击按钮的表情以及文字标识符。但是返回的属性UIImage 和 imageName 是不能被修改的,所以属性上用的 readOnly,头文件如下
#import <UIKit/UIKit.h> typedef void(^emoticonButtonClickBlock)(UIImage * buttonImage,NSString * imageName); @interface EmoticonCell : UICollectionViewCell /** * button上的表情 */ @property(nonatomic,strong,readonly)UIImage * buttonImage; /** * button上表情的名字 */ @property(nonatomic,strong,readonly)NSString * imageName; @end
因为继承了BaseCollectionViewCell,所以在基类中没有实现的方法需要在EmoticonCell类中进行实现,首先实现基类中的两个方法
/** * 设置block回调 * * @param emoticonButtonBlock 回调的代码块 */ -(void)emotionButtonClickBlockHandle:(emoticonButtonClickBlock)emoticonButtonBlock { self.b = emoticonButtonBlock; } /** * 根据表情模型赋值 * * @param emoticon 表情模型 */ -(void)setInformationWithEmoticon:(Emoticon *)emoticon { UIImage * image = [UIImage imageNamed:emoticon.png]; [self setButtonImage:image WithImageName:emoticon.chs]; }
在setInfomationWithEmoticon:方法中用到了一个自定义的设置的方法,是之前写的,又不想删除,所以就起到了一个简化代码的作用,很简单的实现,如下
/** * 设置button上按钮的图片和图片名字 * * @param buttonImage 按钮上的图片 * @param imageName 按钮上图片的名字 */ -(void)setButtonImage:(UIImage *)buttonImage WithImageName:(NSString *)imageName { _buttonImage = buttonImage; _imageName = imageName; //设置button属性 [self.emoticonButton setImage:_buttonImage forState:UIControlStateNormal]; }
因为Cell的基类说到底就是UIView,所以必须要重写两个创建方法,如下
//用纯代码创建的时候走的创建方法 -(instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { [self cellInit]; } return self; } //用xib或者storyboard创建的时候走的创建方法 -(void)awakeFromNib { [self cellInit]; }
因为cellInit是自定义的创建方式,自然每个创建方法都要用,所以楼主打包成一个方法,偷个懒0.0
-(void)cellInit { //初始化按钮 self.emoticonButton = [UIButton buttonWithType:UIButtonTypeCustom]; //设置大小 self.emoticonButton.frame = self.bounds; //注册回调方法 [self.emoticonButton addTarget:self action:@selector(emoticonButtonClick) forControlEvents:UIControlEventTouchUpInside]; //添加button [self addSubview:self.emoticonButton]; }
当button被点击的时候,之前的回调就有用了
/** * 按钮被点击的时候,对父控件进行回调 */ -(void)emoticonButtonClick { //如果自己的回调被赋值后,才进行回调 if (self.b) { self.b(_buttonImage,_imageName); } }
这样自定义的Cell类就完成了。
EmoticonsView(展示表情的视图)
EmoticonsView是在这里面最复杂的一个视图了,与其说它复杂不是因为逻辑复杂,也不是因为代码多,而是这里面用到了一个以前没有接触过的UICollectionView(集合视图)类,之前的一切也都是为了它再做铺垫,但是好处就是他的用法与UITableView(表格视图很像),这也提供了一些参考,话不多说,希望代码的写法能给大家一些启发,自然这里的用法都是最基础的用法,并不能代表这个组件已经完全驾驭。首先因为他不是最后的boss(ViewController),所以也是需要汇报的,自然是少不了回调的,因为用Block回调比较多,所以依旧选择用Block回调,下面是声明文件.h中的声明:
#import <UIKit/UIKit.h> typedef void(^emoticonsViewWithButtonPressedBlock)(UIImage * image, NSString * imageName); @interface EmoticonsView : UIView /** * 设置block回调 * * @param buttonPressedBlock 返回代码块 */ -(void)emoticonsViewWithButtonPressedBlockHandle:(emoticonsViewWithButtonPressedBlock)buttonPressedBlock; @end
接着就是在延展中,加入三个属性对象,分别用来显示表情(collectionView),存储表情的信息(emoticons),以及回调的方法Block(b),但是有一点不同,要用UICollectionView,要遵守三个协议,不是UITableView的两个协议,因为多了一个类似布局的协议,如下
@interface EmoticonsView ()<UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout> //视图集合 @property(nonatomic,strong)UICollectionView * collectionView; //存储表情的数组 @property(nonatomic,strong)NSArray * emoticons; //回调代码块 @property(nonatomic,strong)emoticonsViewWithButtonPressedBlock b; @end
因为是view,所以重写的那两个方法不再赘余,只说明自写的init方法
-(void)viewInit { //配置collectionView [self loadCollectionView]; //注册cell [self registerClassWithCell]; //加载数组 self.emoticons = [self loadEmoticons]; //贴到视图上 [self addSubview:self.collectionView]; //开始适配 [self layoutCollectionView]; }
先从最简单的开始,加载数组,思路是先从plist文件中加载数据,然后通过遍历出的字典,通过字典转模型,再返回处理好的数组,如下
#pragma mark - 表情数组的加载 /** * 加载表情数据 * * @return 返回存储表情的数组 */ -(NSArray *)loadEmoticons { //路径 NSString * path = [[NSBundle mainBundle]pathForResource:@"emoticons" ofType:@"plist"]; //加载数据 NSArray * emoticons = [NSArray arrayWithContentsOfFile:path]; //整合的数组 NSMutableArray * mutableEmoticons = [NSMutableArray array]; //可变数组进行数据整合 for (NSDictionary * infoDict in emoticons) { //字典转模型 Emoticon * emoticon = [Emoticon emoticonWithDictionary:infoDict]; //可变数组添加 [mutableEmoticons addObject:emoticon]; } return [NSArray arrayWithArray:mutableEmoticons]; }
因为没有storyboard直接用UICollectionViewController,所以要结合自定义cell,只能通过在init中进行注册,为什么要单独出一个方法呢,不就是一句话么,如果cell足够多的话,只需要改动这个方法即可,不需要改动init方法。
/** * 注册各种cell */ -(void)registerClassWithCell { //注册cell,让cell的重用标识符是@“Emoticon” [self.collectionView registerClass:[EmoticonCell class] forCellWithReuseIdentifier:@"Emoticon"]; }
倒数第二麻烦的就应该是布局了,虽然代码看起来很爽,但是确实是说,用stroyboard来布局是非常高效的,但楼主用的是代码。需要注意的就是一点,必须先添加到父视图上才可以进行布局,不然会出很多麻烦
-(void)layoutCollectionView { //水平适配 NSArray * horizontal = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_collectionView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_collectionView)]; [self addConstraints:horizontal]; //垂直适配 NSArray * verital = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_collectionView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_collectionView)]; [self addConstraints:verital]; }
最麻烦的就是数UICollectionView了,因为它有着各种协议以及各种配置问题,因为有注释,所以很明确,看一下配置方法
/** * 配置集合视图(CollectionView) */ -(void)loadCollectionView { //集合视图的布局对象,必须有!如果不想设置其他的属性,就只有这句init即可 UICollectionViewFlowLayout * layout = [[UICollectionViewFlowLayout alloc]init]; //水平滚动,也就说布局是竖直优先 layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; //初始化集合视图(UICollenctionView) self.collectionView = [[UICollectionView alloc]initWithFrame:CGRectZero collectionViewLayout:layout]; //手动适配屏幕 self.collectionView.translatesAutoresizingMaskIntoConstraints = NO; //分页显示,否则太滑,继承于ScrollView [self.collectionView setPagingEnabled:YES]; //默认是黑色的 self.collectionView.backgroundColor = [UIColor groupTableViewBackgroundColor]; //不显示水平滚动栏 self.collectionView.showsHorizontalScrollIndicator = NO; //设置代理和数据源 self.collectionView.delegate = self; self.collectionView.dataSource = self; }
首先实现集合视图的数据源方法,首先看两个,很好理解,和UITableView简直就是双胞胎,只不过tableView用row,而CollectionView用item
#pragma mark - UICollectionView DateSource //返回几个组,也是分组的,默认也是1,这个和UITableView一致 - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { return 1; } //返回组中的数据的个数 - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return self.emoticons.count; }
接着就是实现自定义cell的方法,与UItableView稍有不同,但也是很好理解的
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { //获取数据 Emoticon * emoticon = self.emoticons[indexPath.row]; //创建cell BaseCollectionViewCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([emoticon class]) forIndexPath:indexPath]; //避免强引用循环 __weak __block EmoticonsView * copy_self = self; //对cell设置进行的回调 [cell emotionButtonClickBlockHandle:^(UIImage *buttonImage, NSString *imageName) { //如果上报代码块存在 if (copy_self.b) { copy_self.b(buttonImage,imageName); } }]; //设置数据 [cell setInformationWithEmoticon:emoticon]; return cell; }
因为UICollectionViewDelegate的方法没有用到的,所以没有写相关方法,直接用的UICollectionViewDelegateFlowLayout方法,更多方法也可以按住option点击进入开发文档进行查看,方法如下
#pragma mark - UICollectionView DelegateFlowLayout //每个item的大小(可以根据indexPath定制) - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { return CGSizeMake(30, 30); } //每组距离边界的大小,逆时针,上,左,下,右 - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { return UIEdgeInsetsMake(20, 20, 20, 20); }
显示的view完毕
MyTextField (文本框)
MyTextField 其实是继承于UITextView,但是楼主当时打的太快,所以起错了名字,改的时候又太麻烦,所以就不改了,这个类的作用就是能够调用我们之前写好的表情键盘的类,它需要知道目前键盘的类型是啥,也就是一个标志位。为了显得高大上一点,用的枚举typedef enum : NSUInteger { KeyBoardTypeSystem, KeyBoardTypeFace, } KeyBoardType;
声明文件中只需要声明一个可查看键盘状态的属性,一个切换键盘的方法和具体改变键盘的方法即可
@interface MyTextField : UITextView /** * 当前键盘的状态 */ @property(nonatomic,assign,readonly)KeyBoardType currentKeyBoardType; /** * 切换键盘的方法 */ -(void)switchKeyBoard; /** * 改变键盘 * * @param keyBoard 改变键盘的样式 */ -(void)changeKeyBoard:(KeyBoardType)keyBoard; @end
在延展中只需要一个表情视图(EmoticonsView)即可
@interface MyTextField () @property(nonatomic,strong)EmoticonsView * emoticonView; @end
自定义的init方法
-(void)fieldInit { //初始化键盘view self.emoticonView = [[EmoticonsView alloc]initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 200)]; //初始化当前状态 _currentKeyBoardType = KeyBoardTypeSystem; //避免强引用循环 __block __weak MyTextField * copy_self = self; //设置回调 [self.emoticonView emoticonsViewWithButtonPressedBlockHandle:^(UIImage *image, NSString *imageName) { //为text设置内容 copy_self.text = [copy_self.text stringByAppendingString:imageName]; }]; }
实现切换键盘的两个方法即可
切换键盘的方法如下
-(void)switchKeyBoard { switch (self.currentKeyBoardType) { //如果是表情键盘,就换成系统键盘 case KeyBoardTypeFace: [self changeKeyBoard:KeyBoardTypeSystem]; break; //如果是系统键盘,就换成表情键盘 case KeyBoardTypeSystem: [self changeKeyBoard:KeyBoardTypeFace]; break; default: break; } }
改变键盘的方法如下
-(void)changeKeyBoard:(KeyBoardType)keyBoardType { //判断是什么键盘 switch (keyBoardType) { //如果是系统键盘 case KeyBoardTypeSystem: self.inputView = nil;//nil表示系统默认自带的键盘 break; //如果是表情键盘 case KeyBoardTypeFace: self.inputView = self.emoticonView; break; default: break; } _currentKeyBoardType = keyBoardType; //如果是第一响应就要刷新一下 if (self.isFirstResponder) { [self reloadInputViews]; } }
Controller(控制器)
controller算是最后的小老板了,因为之前的铺垫,所以他的逻辑就变得很简单了首先在延展中声明一个切换键盘的 按钮(UIButton) 以及 自定义的文本域(MyTextField) 即可
//文本域 @property(nonatomic,strong)MyTextField * textField; //切换状态的按钮 @property(nonatomic,strong)UIButton * stateButton;
viewDidLoad上,楼主依旧用的是方法进行
#pragma mark - 自带的加载方法 - (void)viewDidLoad { [super viewDidLoad]; //设置背景色 [self.view setBackgroundColor:[UIColor whiteColor]]; //加载按钮 [self loadStateButton]; //适配切换按钮 [self layoutStateButton]; //加载textField [self loadTextView]; //适配textField [self layoutTextView];//注意位置不可随意,必须在button适配好之后才可以,因为它是以button为基准的 }
首先加载button,用storyboard是很简单,因为用的是代码,所以看起来比较复杂,不做过多的解释,相信都能看得懂
/** * 加载键盘状态转换按钮 */ -(void)loadStateButton { //初始化button对象 self.stateButton = [UIButton buttonWithType:UIButtonTypeSystem]; //设置button的title [self.stateButton setTitle:@"切换输入法" forState:UIControlStateNormal]; //解除自动适配 self.stateButton.translatesAutoresizingMaskIntoConstraints = NO; //添加目标动作回调 [self.stateButton addTarget:self action:@selector(stateButtonClick) forControlEvents:UIControlEventTouchUpInside]; //添加组件 [self.view addSubview:self.stateButton]; }
接着是button的适配
/** * 对切换按钮进行适配 */ -(void)layoutStateButton { //水平适配 NSArray * horizontal = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_stateButton]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_stateButton)]; [self.view addConstraints:horizontal]; //垂直适配 NSArray * verital = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-20-[_stateButton]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_stateButton)]; [self.view addConstraints:verital]; }
按钮配置完毕后,就需要适配文本域了,加载方法如下
/** * 加载textField */ -(void)loadTextView { //创建文本对象 self.textField = [[MyTextField alloc]initWithFrame:CGRectZero]; //设置背景色 self.textField.backgroundColor = [UIColor groupTableViewBackgroundColor]; //解除自动适配 self.textField.translatesAutoresizingMaskIntoConstraints = NO; //添加视图 [self.view addSubview:self.textField]; }
为文本域添加约束
/** * 适配文本框 */ -(void)layoutTextView { //水平适配 NSArray * horizontal = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-10-[_textField]-10-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_textField)]; [self.view addConstraints:horizontal]; //垂直布局 NSArray * verital = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[_stateButton]-8-[_textField(150)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_textField,_stateButton)]; [self.view addConstraints:verital]; }
切换按钮的回调方法,因为之前的铺垫,依旧很简单
/** * 切换按钮点击 */ -(void)stateButtonClick { [self.textField switchKeyBoard]; }
基本的功能到此结束。
但是这样完善有一个不舒服的地方,就是输入完毕东西之后,键盘不能自动消失,但是重新加一个按钮又显得很low,所以楼主用的是一个轻击手势,怎么用呢,在延展中加入一个属性
//轻击手势 @property(nonatomic,strong)UITapGestureRecognizer * tapGestureRecognizer;
在viewDidLoad中加入这个方法
//配置手势 [self loadTapGestureRecognizer];
配制方法
/** * 加载轻击手势 */ -(void)loadTapGestureRecognizer { //初始化轻击手势 self.tapGestureRecognizer = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapAction)]; //必须双击 self.tapGestureRecognizer.numberOfTapsRequired = 2; //添加手势 [self.view addGestureRecognizer:self.tapGestureRecognizer]; }
轻击后的回调方法
/** * 轻击手势的目标动作回调 */ -(void)tapAction { //如果是第一响应 if ([self.textField isFirstResponder]) { //撤销键盘,解除第一响应 [self.view endEditing:YES]; } }
这样,双击后键盘就自动撤掉了。更多手势识别可以去看看之前的博客iOS学习-------手势识别,3Q
相关文章推荐
- 127. Word Ladder (Tree, Queue; WFS)
- UITextView 的placeholder
- 集合视图UICollectionView
- storyBoard和用segue切换视图的方法
- UIActivityViewController的使用
- BZOJ 2037: [Sdoi2008]Sue的小球(DP)
- 第二十七篇:QQ好友列表,UITableViewHeaderFooterView用法
- 101. Symmetric Tree (Tree, Queue; DFS, WFS)
- 安装vmware-tools遇The path "" is not a valid path to the 3.8.13-44.1.1.el6uek.x86_64 kernel问题解决
- php multi_query()函数
- SpriteBuilder中的距离关节的min和max距离属性值
- SpriteBuilder中的距离关节的min和max距离属性值
- SpriteBuilder中的距离关节的min和max距离属性值
- duilib入门问题集
- 95. Unique Binary Search Trees II (Tree; DFS)
- AndroidUI 侧滑菜单 DrawerLayout的使用
- AndroidUI 侧滑菜单 DrawerLayout的使用
- 96. Unique Binary Search Trees (Tree; DFS)
- symfony报错:Declaration of testAction::execute() must be compatible with sfComponent::execute($request
- IOS 自定义的UITableViewCell实现UITableView