下面的东西是编写自定义的表情键盘,话不多说,开门见山吧!下面主要用到的知识有MVC, iOS开发中的自动布局,自定义组件的封装与使用,Block回调,CoreData的使用。有的小伙伴可能会问写一个自定义表情键盘肿么这么麻烦?下面将会介绍我们如何用上面提到的东西来定义我们的表情键盘。下面的内容会比较多,这篇博文还是比较有料的。

  还是那句话写技术博客是少不了代码的,下面会结合代码来回顾一下iOS的知识,本篇博文中用到的知识点在前面的博客中都能找到相应的内容,本篇算是一个小小的功能整合。先来张图看一下本app的目录结构。我是根据自己对MVC的理解来构建的目录结构,希望起到抛砖引玉的作用,有好的解决方案欢迎评论或者留言指出。Face文件中存放的时我们的表情图片,Model文件封装的是从sqlite中读取历史头像的组件,View文件中封装的时我们自定义的组件,也就是自定义键盘相关的视图,Controller负责将我们的各个组件组装到一起完成我们想要的功能。下面会一一介绍。

  上面是文件的组织结构,下面为了更为直观的了解我们想要的效果,下面先看几张截图,来直观的感受一下运行效果,上面是竖屏的显示效果,下面是横屏的显示效果。因为在封装自定义键盘中用到了自动布局所以横屏显示或者在更大的屏幕上显示是没问题的,常用表情是用户用过的表情,然后存在Sqlite中,显示时并按时间降序排列。more是用来扩展功能用的接口。话不多说,来的代码才是实在的。

  一.View(自定义视图)

    View文件夹下存放的时我们自定义的视图组件,因为是自定义的组件所以storyboard我们就用不了啦,所有的代码都必须手写,这样才能保证组件使用的灵活性和减少各个组件之间的耦合性,更利于团队之间的合作。在封装组件时要预留好外界可能使用到的接口,和返回该返回的数据。好啦,废话少说,来点干货吧!

    1、FaceView组件的封装:FaceView即负责显示一个个的头像。在使用该组件时要传入要显示的图片和图片对应的文字(如【哈哈】),当点击图片的时候,会通过block回调的形式把该图片的image以及图片文字返回到使用的组件中去,下面是关键代码:

      FaceView.h中的代码如下(下面代码是定义啦相应的Block类型和对外的接口):

  1. #import <UIKit/UIKit.h>
  2.  
  3. //声明表情对应的block,用于把点击的表情的图片和图片信息传到上层视图
  4. typedef void (^FaceBlock) (UIImage *image, NSString *imageText);
  5.  
  6. @interface FaceView : UIView
  7.  
  8. //图片对应的文字
  9. @property (nonatomic, strong) NSString *imageText;
  10. //表情图片
  11. @property (nonatomic, strong) UIImage *headerImage;
  12.  
  13. //设置block回调
  14. -(void)setFaceBlock:(FaceBlock)block;
  15.  
  16. //设置图片,文字
  17. -(void)setImage:(UIImage *) image ImageText:(NSString *) text;
  18.  
  19. @end

      FaceView.m中的代码如下

  1. //
  2. // FaceView.m
  3. // MyKeyBoard
  4. //
  5. // Created by 青玉伏案 on 14-9-16.
  6. // Copyright (c) 2014年 Mrli. All rights reserved.
  7. //
  8.  
  9. #import "FaceView.h"
  10.  
  11. @interface FaceView ()
  12. @property(strong, nonatomic) FaceBlock block;
  13. @property (strong, nonatomic) UIImageView *imageView;
  14. @end
  15.  
  16. @implementation FaceView
  17.  
  18. //初始化图片
  19. - (id)initWithFrame:(CGRect)frame
  20. {
  21. //face的大小
  22. frame.size.height = ;
  23. frame.size.width = ;
  24. self = [super initWithFrame:frame];
  25. if (self) {
  26. self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(, , , )];
  27. [self addSubview:self.imageView];
  28. }
  29. return self;
  30. }
  31.  
  32. -(void) setFaceBlock:(FaceBlock)block
  33. {
  34. self.block = block;
  35. }
  36.  
  37. -(void) setImage:(UIImage *)image ImageText:(NSString *)text
  38. {
  39. //显示图片
  40. [self.imageView setImage:image];
  41.  
  42. //把图片存储起来
  43. self.headerImage = image;
  44.  
  45. self.imageText = text;
  46. }
  47.  
  48. //点击时回调
  49. -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
  50. {
  51. UITouch *touch = [touches anyObject];
  52. CGPoint point = [touch locationInView:self];
  53. //判断触摸的结束点是否在图片中
  54. if (CGRectContainsPoint(self.bounds, point))
  55. {
  56. //回调,把该头像的信息传到相应的controller中
  57. self.block(self.headerImage, self.imageText);
  58. }
  59. }
  60.  
  61. @end

    代码说明:

      主要就是block回调的使用,就是封装了一个自定义的button,具体内容请参考之前的博客“IOS开发之自定义Button(集成三种回调模式)

    2、FunctionView组件的封装,FunctionView就是使用FaceView组件和ScrollView组件把表情加载进来,在实例化FunctionView组件时,我们用到了自动布局来设置ScrollView和下面的Button

      FunctionView.h的代码如下,在.h中留有组件的接口和回调用的Block, plistFileName用于加载我们的资源文件时使用,至于如何使用plist文件,请参考之前的博客:IOS开发之显示微博表情

  1. //
  2. // FunctionView.h
  3. // MyKeyBoard
  4. //
  5. // Created by 青玉伏案 on 14-9-16.
  6. // Copyright (c) 2014年 Mrli. All rights reserved.
  7. //
  8.  
  9. #import <UIKit/UIKit.h>
  10.  
  11. //定义对应的block类型,用于数据的交互
  12. typedef void (^FunctionBlock) (UIImage *image, NSString *imageText);
  13.  
  14. @interface FunctionView : UIView
  15. //资源文件名
  16. @property (nonatomic, strong) NSString *plistFileName;
  17. //接受block块
  18. -(void)setFunctionBlock:(FunctionBlock) block;
  19.  
  20. @end

      FunctionView.m中的代码如下,常用表情是在sqlite中获取的,而全部表情是通过plist文件的信息在Face文件中加载的:

  1. //
  2. // FunctionView.m
  3. // MyKeyBoard
  4. //
  5. // Created by 青玉伏案 on 14-9-16.
  6. // Copyright (c) 2014年 Mrli. All rights reserved.
  7. //
  8.  
  9. #import "FunctionView.h"
  10. #import "FaceView.h"
  11. #import "ImageModelClass.h"
  12. #import "HistoryImage.h"
  13.  
  14. @interface FunctionView()
  15.  
  16. @property (strong, nonatomic) FunctionBlock block;
  17. //暂存表情组件回调的表情和表情文字
  18. @property (strong, nonatomic) UIImage *headerImage;
  19. @property (strong, nonatomic) NSString *imageText;
  20.  
  21. //display我们的表情图片
  22. @property (strong, nonatomic) UIScrollView *headerScrollView;
  23.  
  24. //定义数据模型用于获取历史表情
  25. @property (strong, nonatomic) ImageModelClass *imageModel;
  26.  
  27. @end
  28.  
  29. @implementation FunctionView
  30. - (id)initWithFrame:(CGRect)frame
  31. {
  32. self = [super initWithFrame:frame];
  33. if (self) {
  34.  
  35. //实例化数据模型
  36. self.imageModel =[[ImageModelClass alloc] init];
  37.  
  38. //实例化下面的button
  39. UIButton *faceButton = [[UIButton alloc] initWithFrame:CGRectZero];
  40. faceButton.backgroundColor = [UIColor grayColor];
  41.  
  42. [faceButton setTitle:@"全部表情" forState:UIControlStateNormal];
  43. [faceButton setShowsTouchWhenHighlighted:YES];
  44. [faceButton addTarget:self action:@selector(tapButton1:) forControlEvents:UIControlEventTouchUpInside];
  45. [self addSubview:faceButton];
  46.  
  47. //实例化常用表情按钮
  48. UIButton *moreButton = [[UIButton alloc] initWithFrame:CGRectZero];
  49. moreButton.backgroundColor = [UIColor orangeColor];
  50. [moreButton setTitle:@"常用表情" forState:UIControlStateNormal];
  51. [moreButton setShowsTouchWhenHighlighted:YES];
  52. [moreButton addTarget:self action:@selector(tapButton2:) forControlEvents:UIControlEventTouchUpInside];
  53. [self addSubview:moreButton];
  54.  
  55. //给按钮添加约束
  56. faceButton.translatesAutoresizingMaskIntoConstraints = NO;
  57. moreButton.translatesAutoresizingMaskIntoConstraints = NO;
  58. //水平约束
  59. NSArray *buttonH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[faceButton][moreButton(==faceButton)]|" options: metrics: views:NSDictionaryOfVariableBindings(faceButton,moreButton)];
  60. [self addConstraints:buttonH];
  61.  
  62. //垂直约束
  63. NSArray *button1V = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[faceButton(44)]|" options: metrics: views:NSDictionaryOfVariableBindings(faceButton)];
  64. [self addConstraints:button1V];
  65.  
  66. NSArray *button2V = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[moreButton(44)]|" options: metrics: views:NSDictionaryOfVariableBindings(moreButton)];
  67. [self addConstraints:button2V];
  68.  
  69. //默认显示表情图片
  70. [self tapButton1:nil];
  71.  
  72. }
  73. return self;
  74. }
  75.  
  76. //接受回调
  77. -(void)setFunctionBlock:(FunctionBlock)block
  78. {
  79. self.block = block;
  80. }
  81.  
  82. //点击全部表情按钮回调方法
  83. -(void)tapButton1: (id) sender
  84. {
  85. // 从plist文件载入资源
  86. NSBundle *bundle = [NSBundle mainBundle];
  87. NSString *path = [bundle pathForResource:self.plistFileName ofType:@"plist"];
  88. NSArray *headers = [NSArray arrayWithContentsOfFile:path];
  89.  
  90. if (headers.count == ) {
  91. NSLog(@"访问的plist文件不存在");
  92. }
  93. else
  94. {
  95. //调用headers方法显示表情
  96. [self header:headers];
  97. }
  98. }
  99.  
  100. //点击历史表情的回调方法
  101. -(void) tapButton2: (id) sender
  102. {
  103. //从数据库中查询所有的图片
  104. NSArray *imageData = [self.imageModel queryAll];
  105. //解析请求到的数据
  106. NSMutableArray *headers = [NSMutableArray arrayWithCapacity:imageData.count];
  107.  
  108. //数据实体,相当于javaBean的东西
  109. HistoryImage *tempData;
  110.  
  111. for (int i = ; i < imageData.count; i ++) {
  112. tempData = imageData[i];
  113.  
  114. //解析数据,转换成函数headers要用的数据格式
  115. NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithCapacity:];
  116. [dic setObject:tempData.imageText forKey:@"chs"];
  117. UIImage *image = [UIImage imageWithData:tempData.headerImage];
  118. [dic setObject:image forKey:@"png"];
  119.  
  120. [headers addObject:dic];
  121. }
  122.  
  123. [self header:headers];
  124.  
  125. }
  126.  
  127. //负责把查出来的图片显示
  128. -(void) header:(NSArray *)headers
  129. {
  130. [self.headerScrollView removeFromSuperview];
  131. self.headerScrollView = [[UIScrollView alloc] initWithFrame:CGRectZero];
  132. [self addSubview:self.headerScrollView];
  133.  
  134. //给scrollView添加约束
  135. self.headerScrollView.translatesAutoresizingMaskIntoConstraints = NO;
  136. //水平约束
  137. NSArray *scrollH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-10-[_headerScrollView]-10-|" options: metrics: views:NSDictionaryOfVariableBindings(_headerScrollView)];
  138. [self addConstraints:scrollH];
  139.  
  140. //垂直约束
  141. NSArray *scrolV = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-10-[_headerScrollView]-50-|" options: metrics: views:NSDictionaryOfVariableBindings(_headerScrollView)];
  142. [self addConstraints:scrolV];
  143.  
  144. CGFloat scrollHeight = (self.frame).size.height-;
  145.  
  146. //根据图片量来计算scrollView的Contain的宽度
  147. CGFloat width = (headers.count/(scrollHeight/))*;
  148. self.headerScrollView.contentSize = CGSizeMake(width, scrollHeight);
  149. self.headerScrollView.pagingEnabled = YES;
  150.  
  151. //图片坐标
  152. CGFloat x = ;
  153. CGFloat y = ;
  154.  
  155. //往scroll上贴图片
  156. for (int i = ; i < headers.count; i ++) {
  157. //获取图片信息
  158. UIImage *image;
  159. if ([headers[i][@"png"] isKindOfClass:[NSString class]])
  160. {
  161. image = [UIImage imageNamed:headers[i][@"png"]];
  162. }
  163. else
  164. {
  165. image = headers[i][@"png"];
  166. }
  167.  
  168. NSString *imageText = headers[i][@"chs"];
  169.  
  170. //计算图片位置
  171. y = (i%(int)(scrollHeight/)) * ;
  172. x = (i/(int)(scrollHeight/)) * ;
  173.  
  174. FaceView *face = [[FaceView alloc] initWithFrame:CGRectMake(x, y, , )];
  175. [face setImage:image ImageText:imageText];
  176.  
  177. //face的回调,当face点击时获取face的图片
  178. __weak __block FunctionView *copy_self = self;
  179. [face setFaceBlock:^(UIImage *image, NSString *imageText)
  180. {
  181. copy_self.block(image, imageText);
  182. }];
  183.  
  184. [self.headerScrollView addSubview:face];
  185. }
  186.  
  187. [self.headerScrollView setNeedsDisplay];
  188.  
  189. }
  190.  
  191. @end

      代码说明:

        1、主要是通过对资源文件或者对从数据库中查询的资源进行遍历然后添加到ScrollView中

        2.为了适应不同的屏幕给相应的组件添加了约束

    3.ToolView组件的封装: ToolView就是在主屏幕上下面的类似于TabBar的东西,当键盘出来的时候,ToolView会运动到键盘上面的位置。为了使用不同的屏幕,也需要用自动布局来实现。

      ToolView.h的代码如下:预留组件接口和声明block类型

  1. //
  2. // ToolView.h
  3. // MyKeyBoard
  4. //
  5. // Created by 青玉伏案 on 14-9-16.
  6. // Copyright (c) 2014年 Mrli. All rights reserved.
  7. //
  8.  
  9. /*****************
  10. 封装下面的工具条组件
  11. *****************/
  12. #import <UIKit/UIKit.h>
  13.  
  14. //定义block块变量类型,用于回调,把本View上的按钮的index传到Controller中
  15. typedef void (^ToolIndex) (NSInteger index);
  16.  
  17. @interface ToolView : UIView
  18.  
  19. //块变量类型的setter方法
  20. -(void)setToolIndex:(ToolIndex) toolBlock;
  21.  
  22. @end

      ToolView.m的代码实现:

  1. //
  2. // ToolView.m
  3. // MyKeyBoard
  4. //
  5. // Created by 青玉伏案 on 14-9-16.
  6. // Copyright (c) 2014年 Mrli. All rights reserved.
  7. //
  8.  
  9. #import "ToolView.h"
  10.  
  11. @interface ToolView ()
  12.  
  13. //定义ToolIndex类型的block,用于接受外界传过来的block
  14. @property (nonatomic, strong) ToolIndex myBlock;
  15.  
  16. @end
  17.  
  18. @implementation ToolView
  19.  
  20. - (id)initWithFrame:(CGRect)frame
  21. {
  22. self = [super initWithFrame:frame];
  23. if (self) {
  24.  
  25. //1初始化表情按钮
  26. UIButton *faceButton = [[UIButton alloc] initWithFrame:CGRectZero];
  27. faceButton.backgroundColor = [UIColor orangeColor];
  28. [faceButton setTitle:@"表情" forState:UIControlStateNormal];
  29. [faceButton setShowsTouchWhenHighlighted:YES];
  30. [faceButton addTarget:self action:@selector(tapFaceButton:) forControlEvents:UIControlEventTouchUpInside];
  31. [self addSubview:faceButton];
  32.  
  33. //初始化更多按钮
  34. UIButton *moreButton = [[UIButton alloc] initWithFrame:CGRectZero];
  35. moreButton.backgroundColor = [UIColor grayColor];
  36. [moreButton setTitle:@"More" forState:UIControlStateNormal];
  37. [moreButton setShowsTouchWhenHighlighted:YES];
  38. [moreButton addTarget:self action:@selector(tapMoreButton:) forControlEvents:UIControlEventTouchUpInside];
  39. [self addSubview:moreButton];
  40.  
  41. //给我们的按钮添加约束来让按钮来占满toolView;
  42. faceButton.translatesAutoresizingMaskIntoConstraints = NO;
  43. moreButton.translatesAutoresizingMaskIntoConstraints = NO;
  44.  
  45. //添加水平约束
  46. NSArray *buttonH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[faceButton][moreButton(==faceButton)]|" options: metrics: views:NSDictionaryOfVariableBindings(faceButton,moreButton)];
  47. [self addConstraints:buttonH];
  48.  
  49. //添加垂直约束
  50. NSArray *button1V = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[faceButton]|" options: metrics: views:NSDictionaryOfVariableBindings(faceButton)];
  51. [self addConstraints:button1V];
  52.  
  53. NSArray *button2V = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[moreButton]|" options: metrics: views:NSDictionaryOfVariableBindings(moreButton)];
  54. [self addConstraints:button2V];
  55.  
  56. }
  57. return self;
  58. }
  59.  
  60. //接受传入的回调
  61. -(void) setToolIndex:(ToolIndex)toolBlock
  62. {
  63. self.myBlock = toolBlock;
  64. }
  65.  
  66. //点击表情按钮要回调的方法
  67. -(void) tapFaceButton: (id) sender
  68. {
  69. self.myBlock();
  70. }
  71.  
  72. //点击more要回调的方法
  73. -(void) tapMoreButton: (id) sender
  74. {
  75. self.myBlock();
  76. }
  77.  
  78. @end

      代码说明:

        主要是对block回调的应用和给相应的组件添加相应的约束

    4.MoreView组件的封装代码就不往上贴啦,和上面的类似,下面是调用MoreView组件的运行效果,有兴趣的读者请自行编写,以上就是视图部分的代码了

     

  二. Mode部分的内容:

    1.先定义我们要使用的数据模型,数据模型如下,time是使用表情的时间,用于排序。

    2.下面编写我们的ImageModelClass类,里面封装了我们操作数据要用的方法

      ImageModelClass.h的代码如下,主要是预留的对外的接口:

  1. //
  2. // ImageModelClass.h
  3. // MyKeyBoard
  4. //
  5. // Created by 青玉伏案 on 14-9-16.
  6. // Copyright (c) 2014年 Mrli. All rights reserved.
  7. //
  8.  
  9. #import <Foundation/Foundation.h>
  10. #import <CoreData/CoreData.h>
  11. #import "HistoryImage.h"
  12.  
  13. @interface ImageModelClass : NSObject
  14. //保存数据
  15. -(void)save:(NSData *) image ImageText:(NSString *) imageText;
  16. //查询所有的图片
  17. -(NSArray *) queryAll;
  18. @end

      ImageModelClass.m的代码如下,主要是用CoreData对sqlite的操作:

  1. //
  2. // ImageModelClass.m
  3. // MyKeyBoard
  4. //
  5. // Created by 青玉伏案 on 14-9-16.
  6. // Copyright (c) 2014年 Mrli. All rights reserved.
  7. //
  8.  
  9. #import "ImageModelClass.h"
  10.  
  11. @interface ImageModelClass ()
  12.  
  13. @property (nonatomic, strong) NSManagedObjectContext *manager;
  14.  
  15. @end
  16.  
  17. @implementation ImageModelClass
  18. - (instancetype)init
  19. {
  20. self = [super init];
  21. if (self) {
  22. //通过上下文获取manager
  23. UIApplication *application = [UIApplication sharedApplication];
  24. id delegate = application.delegate;
  25. self.manager = [delegate managedObjectContext];
  26. }
  27. return self;
  28. }
  29.  
  30. -(void)save:(NSData *)image ImageText:(NSString *)imageText
  31. {
  32. if (image != nil) {
  33. NSArray *result = [self search:imageText];
  34.  
  35. HistoryImage *myImage;
  36.  
  37. if (result.count == )
  38. {
  39. myImage = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([HistoryImage class]) inManagedObjectContext:self.manager];
  40. myImage.imageText = imageText;
  41. myImage.headerImage = image;
  42. myImage.time = [NSDate date];
  43. }
  44. else
  45. {
  46. myImage = result[];
  47. myImage.time = [NSDate date];
  48. }
  49.  
  50. //存储实体
  51. NSError *error = nil;
  52. if (![self.manager save:&error]) {
  53. NSLog(@"保存出错%@", [error localizedDescription]);
  54. }
  55.  
  56. }
  57.  
  58. }
  59.  
  60. //查找
  61. -(NSArray *)search:(NSString *) image
  62. {
  63. NSArray *result;
  64.  
  65. //新建查询条件
  66. NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:NSStringFromClass([HistoryImage class])];
  67.  
  68. //添加谓词
  69. NSPredicate *predicate = [NSPredicate predicateWithFormat:@"imageText=%@",image];
  70.  
  71. //把谓词给request
  72. [fetchRequest setPredicate:predicate];
  73.  
  74. //执行查询
  75. NSError *error = nil;
  76. result = [self.manager executeFetchRequest:fetchRequest error:&error];
  77. if (error) {
  78. NSLog(@"查询错误:%@", [error localizedDescription]);
  79. }
  80. return result;
  81. }
  82.  
  83. //查询所有的
  84. -(NSArray *) queryAll
  85. {
  86. //新建查询条件
  87. NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:NSStringFromClass([HistoryImage class])];
  88.  
  89. //添加排序规则
  90. //定义排序规则
  91. NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"time" ascending:NO];
  92.  
  93. //添加排序规则
  94. [fetchRequest setSortDescriptors:@[sortDescriptor]];
  95.  
  96. //执行查询
  97. NSError *error = nil;
  98. NSArray *result = [self.manager executeFetchRequest:fetchRequest error:&error];
  99. if (error) {
  100. NSLog(@"查询错误:%@", [error localizedDescription]);
  101. }
  102.  
  103. return result;
  104. }
  105.  
  106. @end

      代码说明:

        1.保存图片时先查找图片是否存在,如果存在则更新时间,如果不存在则插入数据(写到这感觉想在用Hibernate写东西)。

  三.Controller部分,把上面的组件进行组装

    1.MainViewController.m中的延展部分的代码如下:

  1. @interface MainViewController ()
  2.  
  3. //自定义组件
  4. @property (nonatomic, strong) ToolView *toolView;
  5.  
  6. @property (nonatomic, strong) FunctionView *functionView;
  7.  
  8. @property (nonatomic, strong) MoreView *moreView;
  9.  
  10. //系统组件
  11. @property (strong, nonatomic) IBOutlet UITextView *myTextView;
  12.  
  13. @property (strong, nonatomic) NSDictionary *keyBoardDic;
  14.  
  15. @property (strong, nonatomic) IBOutlet UIImageView *imageView;
  16.  
  17. @property (strong, nonatomic) NSString *sendString;
  18.  
  19. //数据model
  20. @property (strong, nonatomic) ImageModelClass *imageMode;
  21.  
  22. @property (strong, nonatomic)HistoryImage *tempImage;
  23.  
  24. @end

    2.在viewDidLoad中进行组件的初始化和实现组件的Block回调,代码如下

  1. - (void)viewDidLoad
  2. {
  3. [super viewDidLoad];
  4.  
  5. //从sqlite中读取数据
  6. self.imageMode = [[ImageModelClass alloc] init];
  7.  
  8. //实例化FunctionView
  9. self.functionView = [[FunctionView alloc] initWithFrame:CGRectMake(, , , )];
  10. self.functionView.backgroundColor = [UIColor blackColor];
  11.  
  12. //设置资源加载的文件名
  13. self.functionView.plistFileName = @"emoticons";
  14.  
  15. __weak __block MainViewController *copy_self = self;
  16. //获取图片并显示
  17. [self.functionView setFunctionBlock:^(UIImage *image, NSString *imageText)
  18. {
  19. NSString *str = [NSString stringWithFormat:@"%@%@",copy_self.myTextView.text, imageText];
  20.  
  21. copy_self.myTextView.text = str;
  22. copy_self.imageView.image = image;
  23.  
  24. //把使用过的图片存入sqlite
  25. NSData *imageData = UIImagePNGRepresentation(image);
  26. [copy_self.imageMode save:imageData ImageText:imageText];
  27. }];
  28.  
  29. //实例化MoreView
  30. self.moreView = [[MoreView alloc] initWithFrame:CGRectMake(, , , )];
  31. self.moreView.backgroundColor = [UIColor blackColor];
  32. [self.moreView setMoreBlock:^(NSInteger index) {
  33. NSLog(@"MoreIndex = %d",index);
  34. }];
  35.  
  36. //进行ToolView的实例化
  37. self.toolView = [[ToolView alloc] initWithFrame:CGRectZero];
  38. self.toolView.backgroundColor = [UIColor blackColor];
  39. [self.view addSubview:self.toolView];
  40.  
  41. //给ToolView添加约束
  42. //开启自动布局
  43. self.toolView.translatesAutoresizingMaskIntoConstraints = NO;
  44.  
  45. //水平约束
  46. NSArray *toolHConstraint = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_toolView]|" options: metrics: views:NSDictionaryOfVariableBindings(_toolView)];
  47. [self.view addConstraints:toolHConstraint];
  48.  
  49. //垂直约束
  50. NSArray *toolVConstraint = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[_toolView(44)]|" options: metrics: views:NSDictionaryOfVariableBindings(_toolView)];
  51. [self.view addConstraints:toolVConstraint];
  52.  
  53. //回调toolView中的方法
  54. [self.toolView setToolIndex:^(NSInteger index)
  55. {
  56. NSLog(@"%d", index);
  57.  
  58. switch (index) {
  59. case :
  60. [copy_self changeKeyboardToFunction];
  61. break;
  62.  
  63. case :
  64. [copy_self changeKeyboardToMore];
  65. break;
  66.  
  67. default:
  68. break;
  69. }
  70.  
  71. }];
  72.  
  73. //当键盘出来的时候通过通知来获取键盘的信息
  74. //注册为键盘的监听着
  75. NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
  76. [center addObserver:self selector:@selector(keyNotification:) name:UIKeyboardWillChangeFrameNotification object:nil];
  77.  
  78. //给键盘添加dan
  79. //TextView的键盘定制回收按钮
  80. UIToolbar * toolBar = [[UIToolbar alloc]initWithFrame:CGRectMake(, , , )];
  81.  
  82. UIBarButtonItem * item1 = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(tapDone:)];
  83. UIBarButtonItem * item2 = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
  84. UIBarButtonItem * item3 = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
  85. toolBar.items = @[item2,item1,item3];
  86.  
  87. self.myTextView.inputAccessoryView =toolBar;
  88.  
  89. }

    3.当横竖屏幕切换时设置自定义键盘的高度

  1. -(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
  2. {
  3. //纵屏
  4. if (UIInterfaceOrientationIsPortrait(toInterfaceOrientation)) {
  5. CGRect frame = self.functionView.frame;
  6. frame.size.height = ;
  7. self.functionView.frame = frame;
  8. self.moreView.frame = frame;
  9.  
  10. }
  11. //横屏
  12. if (UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) {
  13. CGRect frame = self.functionView.frame;
  14. frame.size.height = ;
  15. self.functionView.frame = frame;
  16. self.moreView.frame = frame;
  17. }
  18. }

    4.当键盘出来的时候,改变toolView的位置,通过键盘的通知来实现。当横屏的时候键盘的坐标系和我们当前的Frame的坐标系不一样所以当横屏时得做一坐标系的转换,代码如下;

  1. //当键盘出来的时候改变toolView的位置(接到键盘出来的通知要做的方法)
  2. -(void) keyNotification : (NSNotification *) notification
  3. {
  4. NSLog(@"%@", notification.userInfo);
  5.  
  6. self.keyBoardDic = notification.userInfo;
  7. //获取键盘移动后的坐标点的坐标点
  8. CGRect rect = [self.keyBoardDic[@"UIKeyboardFrameEndUserInfoKey"] CGRectValue];
  9.  
  10. //把键盘的坐标系改成当前我们window的坐标系
  11. CGRect r1 = [self.view convertRect:rect fromView:self.view.window];
  12.  
  13. [UIView animateWithDuration:[self.keyBoardDic[UIKeyboardAnimationDurationUserInfoKey] floatValue] animations:^{
  14.  
  15. //动画曲线
  16. [UIView setAnimationCurve:[self.keyBoardDic[UIKeyboardAnimationCurveUserInfoKey] doubleValue]];
  17.  
  18. CGRect frame = self.toolView.frame;
  19.  
  20. frame.origin.y = r1.origin.y - frame.size.height;
  21.  
  22. //根据键盘的高度来改变toolView的高度
  23. self.toolView.frame = frame;
  24. }];
  25. }

    5.系统键盘和自定义键盘切换的代码如下:

  1. //切换键盘的方法
  2. -(void) changeKeyboardToFunction
  3. {
  4. if ([self.myTextView.inputView isEqual:self.functionView])
  5. {
  6. self.myTextView.inputView = nil;
  7. [self.myTextView reloadInputViews];
  8. }
  9. else
  10. {
  11. self.myTextView.inputView = self.functionView;
  12. [self.myTextView reloadInputViews];
  13. }
  14.  
  15. if (![self.myTextView isFirstResponder])
  16. {
  17. [self.myTextView becomeFirstResponder];
  18. }
  19. }

    

  以上就是上面展示效果的核心代码了,在做的时候感觉难点在于如何进行屏幕适配,尤其是当屏幕横过来的时候键盘的坐标系和我们frame的坐标系不同,得做一个转换。发表博客的目的是想起到抛砖引玉的作用,有好的东西希望大家相互交流一下。笔者水平有限难免有偏颇之处,欢迎批评指正。

  Demo地址:https://github.com/lizelu/CustomeFaceKeyBoard

iOS开发之自定义表情键盘(组件封装与自动布局)的更多相关文章

  1. iOS swift 关于自定义表情键盘

    目录 输入框 键盘监听 键盘切换 表情装载 表情加载 表情输入 表情输出 表情显示 结束语 demo下载 demo图片: 输入框 为了让输入框能够随着用户输入内容变化自动变化高度,这里的输入框使用UI ...

  2. iOS开发之微信聊天工具栏的封装

    之前山寨了一个新浪微博(iOS开发之山寨版新浪微博小结),这几天就山寨个微信吧.之前已经把微信的视图结构简单的拖了一下(IOS开发之微信山寨版),今天就开始给微信加上具体的实现功能,那么就先从微信的聊 ...

  3. iOS开发UI篇—核心动画(UIView封装动画)

    iOS开发UI篇—核心动画(UIView封装动画) 一.UIView动画(首尾) 1.简单说明 UIKit直接将动画集成到UIView类中,当内部的一些属性发生改变时,UIView将为这些改变提供动画 ...

  4. 【好程序员笔记分享】——iOS开发之纯代码键盘退出

    -iOS培训,iOS学习-------型技术博客.期待与您交流!------------ iOS开发之纯代码键盘退出(非常简单)     iOS开发之纯代码键盘退出 前面说到了好几次关于键盘退出的,但 ...

  5. 详解iOS开发之自定义View

    iOS开发之自定义View是本文要将介绍的内容,iOS SDK中的View是UIView,我们可以很方便的自定义一个View.创建一个 Window-based Application程序,在其中添加 ...

  6. ios开发之--仿(微信)自定义表情键盘

    先附上demo:https://github.com/hgl753951/CusEmoji.git 效果图如下:

  7. IOS开发之自定义键盘

     本文转载至 http://blog.csdn.net/majiakun1/article/details/41242069 实际开发过程中,会有自定义键盘的需求,比如,需要添加一个表情键盘.本文提供 ...

  8. Android开发案例 - 自定义虚拟键盘

    所有包含IM功能的App(如微信, 微博, QQ, 支付宝等)都提供了Emoji表情之类的虚拟键盘,  如下图:    本文只着重介绍如何实现输入法键盘和自定义虚拟键盘的流畅切换, 而不介绍如何实现虚 ...

  9. 【Swift】IOS开发中自定义转场动画

    在IOS开发中,我们model另外一个控制器的时候,一般都使用默认的转场动画. 其实我们可以自定义一些转场动画.达到不同的转场效果. 步骤如下:(photoBrowser是目标控制器) 1.在源控制器 ...

随机推荐

  1. jquery基本

    对于jquery属性的访问: //对于bool值的属性,元素标签中如果写了这个属性,attr能够获取到,如果没有写,就获取不到. 如:<input type="checkbox&quo ...

  2. log4net写入mysql完整例子

    1,创建表log   CREATE TABLE `log` ( `id`  int(11) NOT NULL AUTO_INCREMENT , `log_datetime`  timestamp NO ...

  3. ExecutorService与ThreadPoolTaskExecutor

    1.ExecutorService private static ExecutorService exec = null; public static ExecutorService getExecu ...

  4. json相关的一些用法

    一. json可以表示3种类型的值:   简单值 . 对象. 数组    表示对象时:>1. 没有变量的概念 ,所以不用申明变量                    >2. 没有末尾结束 ...

  5. replace实现正则过滤替换非法字符

    html+js结构如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http: ...

  6. iOS app上架需要提前准备的东西

    APP icon,要求1024*1024并且不能有圆角效果. 不同屏幕的截图 3.5的,4的,4.7的,5.5的 测试账号,即登录的账号密码(不能删除或更改的) 联系人电话,电子邮件 对项目的描述 关 ...

  7. 怎么可以让div自适应屏幕的高度?(已解决)

    主要解决问题的方法是用JS脚本. 先看布局, 一个div是首部,另一个div是主体,主体包含左侧菜单和右侧内容. 我想把主体div的高度自适应屏幕剩余区域,怎么做? 首先,获取可见区域的高度,docu ...

  8. 控制TextField的内容长度

    参考如下代码(下例是控制设置交易密码,控制6位): - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [ ...

  9. CoolPlist 帧动画自动生成工具

    工具英文名称:CoolPlist作者: 陈前帆 thinkingMan | sonny 邮箱: 625936034@qq.com | chenqianfan1@163.com电话: 136704713 ...

  10. 系统吞吐量(TPS)、用户并发量、性能测试概念和公式

    分享一个概念: http://www.ha97.com/5095.html