自定义表情键盘
先看效果图
屏幕快照 2016-06-15 下午8.24.41.png
实现思路
1.在一个view上面加一个collectionView和一个page control
2.每一个item是一个模型,点击一个item传一个block,block里面装的是一个模型对象
3.每个模型有三个属性,分别是image,title,textToPut,将模型的title属性作为呈现在输入的textview上。
4.我是将输入的字符进行遍历,看有没有表情,有的话就解析出来,没有就输出文字,解析的话是找图片名字一样的字符串,就显示这个表情,我的图片名字都是对应改了的。
下面上代码
定义的模型
#import <UIKit/UIKit.h>
@interface MCIExpressionModel : NSObject
@property(nonatomic,copy)NSString *title;
@property(nonatomic,strong)UIImage *image;
@property(nonatomic,copy)NSString *textToInput;
@end
定义的cell
#import <UIKit/UIKit.h>
@class MCIExpressionModel;
typedef void (^sendExpressModelBlock)(MCIExpressionModel *expressionModel);
@interface ExpressionView : UIView
//@property (nonatomic,unsafe_unretained) Class ExpressionCellClass;
-(void)sendExpressModel:(sendExpressModelBlock)block;
@end
#import "ExpressionCell.h"
@interface ExpressionCell()
@end
@implementation ExpressionCell
-(id)initWithFrame:(CGRect)frame{
if (self=[super initWithFrame:frame]) {
UIButton *button=[UIButton buttonWithType:UIButtonTypeCustom];
button.userInteractionEnabled=NO;
button.frame=self.contentView.bounds;
[self.contentView addSubview:button];
self.expressionButton=button;
}
return self;
}
-(void)setExpressionModel:(MCIExpressionModel *)expressionModel{
_expressionModel=expressionModel;
[self.expressionButton setTitle:nil forState:UIControlStateNormal];
[self.expressionButton setImage:self.expressionModel.image forState:UIControlStateNormal];
}
- (void)setSelected:(BOOL)selected {
[super setSelected:selected];
[self.subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([obj respondsToSelector:@selector(setSelected:)]) {
[obj setSelected:selected];
}
}];
}
@end
自定义view
#import "ExpressionView.h"
#import "ExpressionCell.h"
#import "MCIExpressionModel.h"
#import "ExpressionCillectionLayout.h"
@interface ExpressionView()<UICollectionViewDataSource,UICollectionViewDelegate>
@property(nonatomic,strong)UICollectionView *expCollectionView;
@property(nonatomic,strong)UIPageControl *expPageControl;
@property(nonatomic,strong)NSArray *expressionArray;
@property(nonatomic,copy)sendExpressModelBlock sendExpressModelBlock;
//@property(nonatomic,strong)UICollectionViewFlowLayout *expressionLayout;
@end
@implementation ExpressionView
//@synthesize ExpressionCellClass=_ExpressionCellClass;
//-(Class)ExpressionCellClass{
// if (!_ExpressionCellClass) {
// _ExpressionCellClass=[ExpressionCell class];
// }
// return _ExpressionCellClass;
//}
//
//
//-(void)setExpressionCellClass:(Class)ExpressionCellClass{
// if ([ExpressionCellClass isSubclassOfClass:[ExpressionCell class]]) {
// _ExpressionCellClass = ExpressionCellClass;
// }
//}
//-(UICollectionViewFlowLayout *)expressionLayout{
// if (!_expressionLayout) {
// ExpressionCillectionLayout *layout=[[ExpressionCillectionLayout alloc]init];
// layout.itemSize = CGSizeMake(38, 38);
// layout.pageContentInsets = UIEdgeInsetsMake(5, 5, 5, 5);
// layout.itemSpacing = 0;
// layout.lineSpacing = 0;
// _expressionLayout=layout;
// }
// return _expressionLayout;
//}
-(void)sendExpressModel:(sendExpressModelBlock)block{
self.sendExpressModelBlock=block;
}
- (NSArray *)expressionArray
{
if (_expressionArray == nil) {
self.expressionArray = [NSArray array];
}
[self.expCollectionView registerClass:[ExpressionCell class] forCellWithReuseIdentifier:@"CELLID"];
MCIExpressionModel *exp=[[MCIExpressionModel alloc]init];
exp.image=[UIImage imageNamed:@"睡@2x"];
exp.textToInput=@"[睡]";
exp.title=@"[睡@2x]";
MCIExpressionModel *exp2=[[MCIExpressionModel alloc]init];
exp2.image=[UIImage imageNamed:@"阴险@2x"];
exp2.textToInput=@"[阴险]";
exp2.title=@"[阴险@2x]";
MCIExpressionModel *exp3=[[MCIExpressionModel alloc]init];
exp3.image=[UIImage imageNamed:@"快哭了@2x"];
exp3.textToInput=@"[快哭了]";
exp3.title=@"[快哭了@2x]";
MCIExpressionModel *exp4=[[MCIExpressionModel alloc]init];
exp4.image=[UIImage imageNamed:@"委屈@2x"];
exp4.textToInput=@"[委屈]";
exp4.title=@"[委屈@2x]";
MCIExpressionModel *exp5=[[MCIExpressionModel alloc]init];
exp5.image=[UIImage imageNamed:@"发呆@2x"];
exp5.textToInput=@"[发呆]";
exp5.title=@"[发呆@2x]";
_expressionArray=@[exp,exp2,exp3,exp4,exp5,exp,exp,exp,exp,exp,exp,exp,exp,exp,exp,exp,exp,exp,exp,exp,exp,exp,exp,exp,exp,exp,exp,exp,exp,exp,exp,exp3];
return _expressionArray;
}
-(id)initWithFrame:(CGRect)frame{
self=[super initWithFrame:frame];
ExpressionCillectionLayout *layout=[[ExpressionCillectionLayout alloc]init];
layout.itemSize = CGSizeMake(38, 38);
layout.pageContentInsets = UIEdgeInsetsMake(5, 5, 5, 5);
layout.itemSpacing = 0;
layout.lineSpacing = 0;
UICollectionView *expCollectionView=[[UICollectionView alloc]initWithFrame:CGRectMake(0, 23, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds) - 23) collectionViewLayout:layout];
expCollectionView.autoresizingMask=UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin;
expCollectionView.delegate=self;
expCollectionView.dataSource=self;
expCollectionView.backgroundColor=[UIColor clearColor];
expCollectionView.pagingEnabled=YES;
expCollectionView.showsHorizontalScrollIndicator=NO;
expCollectionView.showsVerticalScrollIndicator=NO;
self.expCollectionView=expCollectionView;
[self addSubview:expCollectionView];
// [expCollectionView mas_makeConstraints:^(MASConstraintMaker *make) {
// make.left.top.right.equalTo(self);
// make.bottom.equalTo(self.expPageControl).offset(-10);
// }];
UIPageControl *pageControl=[[UIPageControl alloc]initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.bounds), 23)];
pageControl.userInteractionEnabled=NO;
pageControl.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin;
self.expPageControl=pageControl;
[self addSubview:pageControl];
// [pageControl mas_makeConstraints:^(MASConstraintMaker *make) {
// make.centerX.equalTo(self);
// make.top.equalTo(expCollectionView).offset(10);
// make.bottom.equalTo(self);
//
// }];
return self;
}
#pragma mark - CollectionView Delegate & DataSource
-(void)refreshPageControl{
//ceil返回大于或者等于指定表达式的最小整数
self.expPageControl.numberOfPages=ceil(self.expCollectionView.contentSize.width)/CGRectGetWidth(self.expCollectionView.bounds);
//floor向下取整
self.expPageControl.currentPage=floor(self.expCollectionView.contentOffset.x/CGRectGetWidth(self.expCollectionView.bounds));
}
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
[self refreshPageControl];
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
dispatch_async(dispatch_get_main_queue(), ^{
[self refreshPageControl];
});
return self.expressionArray.count;
}
-(UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
ExpressionCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:@"CELLID" forIndexPath:indexPath];
cell.expressionModel=self.expressionArray[indexPath.row];
return cell;
}
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
[collectionView deselectItemAtIndexPath:indexPath animated:YES];
MCIExpressionModel *expModel=self.expressionArray[indexPath.item];
//GCBlockInvoke(self.sendExpressModelBlock,expModel);
self.sendExpressModelBlock(expModel);
NSLog(@"%@",expModel.textToInput);
}
@end
#import <UIKit/UIKit.h>
#import"expressionModel.h"
typedef void (^sendExpressModelBlock)(MCIExpressionModel *expressionModel);
@interface ExpressionView : UIView
//@property (nonatomic,unsafe_unretained) Class ExpressionCellClass;
-(void)sendExpressModel:(sendExpressModelBlock)block;
@end
自定义layout
#import <UIKit/UIKit.h>
@interface ExpressionCillectionLayout : UICollectionViewLayout
@property (nonatomic) CGSize itemSize;
@property (nonatomic) CGFloat lineSpacing;
@property (nonatomic) CGFloat itemSpacing;
@property (nonatomic) UIEdgeInsets pageContentInsets;
@end
#import "ExpressionCillectionLayout.h"
@interface ExpressionCillectionLayout()
@property (nonatomic,readonly) NSInteger numberOfItems;
@property (nonatomic,readonly) CGSize pageSize;
@property (nonatomic,readonly) NSInteger numberOfItemsPerPage;
@property (nonatomic,readonly) NSInteger numberOfRowsPerPage;
@property (nonatomic,readonly) NSInteger numberOfItemsPerRow;
@property (nonatomic,readonly) CGSize avaliableSizePerPage;
@end
@implementation ExpressionCillectionLayout
- (NSInteger)numberOfItems {
//只有一个section.
NSInteger section = 0;
NSInteger numberOfItems = [self.collectionView.dataSource collectionView:self.collectionView numberOfItemsInSection:section];
return numberOfItems;
}
- (CGSize)pageSize {
return self.collectionView.bounds.size;
}
- (CGSize)avaliableSizePerPage {
return (CGSize){
self.pageSize.width - self.pageContentInsets.left - self.pageContentInsets.right,
self.pageSize.height - self.pageContentInsets.top - self.pageContentInsets.bottom
};
}
- (NSInteger)numberOfItemsPerRow {
return floor((self.avaliableSizePerPage.width + self.itemSpacing)/(self.itemSize.width + self.itemSpacing)) ?: 1;
}
- (NSInteger)numberOfRowsPerPage {
return floor((self.avaliableSizePerPage.height + self.lineSpacing)/(self.itemSize.height + self.lineSpacing)) ?: 1;
}
- (NSInteger)numberOfItemsPerPage {
return self.numberOfItemsPerRow * self.numberOfRowsPerPage;
}
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
if (CGSizeEqualToSize(self.collectionView.bounds.size, newBounds.size)) {
return NO;
}else{
return YES;
}
}
- (CGSize)collectionViewContentSize {
CGFloat width = ceil((float)self.numberOfItems/self.numberOfItemsPerPage) * self.pageSize.width;
CGFloat height = self.pageSize.height;
return CGSizeMake(width, height);
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
NSInteger index = indexPath.row;
NSInteger page = floor((float)index/self.numberOfItemsPerPage);
NSInteger row = floor((float)(index % self.numberOfItemsPerPage)/self.numberOfItemsPerRow);
NSInteger n = index % self.numberOfItemsPerRow;
CGRect frame = (CGRect){
{page * self.pageSize.width + self.pageContentInsets.left + n*(self.itemSize.width + self.itemSpacing),
self.pageContentInsets.top + row*(self.itemSize.height + self.lineSpacing)},
self.itemSize
};
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
attributes.frame = frame;
return attributes;
}
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
NSMutableArray *array = [NSMutableArray array];
for (int i=0; i<self.numberOfItems; i++){
UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
if (CGRectIntersectsRect(rect, attributes.frame)) {
[array addObject:attributes];
}
}
return [array copy];
}
@end
textViewde扩展
#import <UIKit/UIKit.h>
@interface UITextView (expression)
- (void)setCommentTextView:(NSString *)content;
-(void)getMessageRange:(NSString*)message :(NSMutableArray*)array ;
- (void)getUserNameRange:(NSString *)message;
@end
#import "UITextView+expression.h"
@implementation UITextView (expression)
//将每次输入的字段进行解析,如果有表情,则将表情解析完以后显示图片,没有则直接显示文字
- (void)setCommentTextView:(NSString *)content
{
self.text = @"";
@try {
NSMutableArray *imageArr = [NSMutableArray arrayWithCapacity:0];
[self getMessageRange:content :imageArr];
// NSLog(@"%@",imageArr);
[imageArr enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(@"%@",obj);
NSString *contentPartStr = [NSString stringWithFormat:@"%@",obj];
if (contentPartStr.length > 0) {
NSString *firstC = [obj substringWithRange:NSMakeRange(0, 1)];
NSAttributedString *attributedStr;
if ([firstC isEqualToString:@"[" ]) {
NSRange firstRange = [obj rangeOfString:@"["];
NSRange secondRange = [obj rangeOfString:@"]"];
NSUInteger length = secondRange.location - firstRange.location;
NSRange imageNameRange = NSMakeRange(1, length - 1);
NSString *imageName = [obj substringWithRange:imageNameRange];
NSTextAttachment *attachment = [[NSTextAttachment alloc]init];
NSLog(@"------%@",obj);
attachment.image = [UIImage imageNamed:imageName];
attachment.bounds = CGRectMake(0, 0, 20, 20);
attributedStr = [[NSAttributedString alloc]initWithString:@""];
attributedStr = [NSAttributedString attributedStringWithAttachment:attachment];
}else{
attributedStr = [[NSAttributedString alloc]initWithString:obj];
}
[self.textStorage appendAttributedString:attributedStr];
}
}];
}
@catch (NSException *exception) {
NSLog(@"%@",exception);
}
@finally {
}
}
-(void)getMessageRange:(NSString*)message :(NSMutableArray*)array {
NSRange rangeL = [message rangeOfString:@"["];
NSRange rangeR = [message rangeOfString:@"]"];
//判断当前字符串是否还有表情的标志。
if (rangeL.length && rangeR.length) {
if (rangeL.location > 0) {
[array addObject:[message substringToIndex:rangeL.location]];
[array addObject:[message substringWithRange:NSMakeRange(rangeL.location, rangeR.location + 1 - rangeL.location)]];
NSString *str = [message substringFromIndex:rangeR.location + 1];
[self getMessageRange:str :array];
}
else {
NSString *nextstr = [message substringWithRange:NSMakeRange(rangeL.location, rangeR.location + 1 - rangeL.location)];
//排除“”空字符串
if (![nextstr isEqualToString:@""]) {
[array addObject:nextstr];
NSString *str = [message substringFromIndex:rangeR.location + 1];
[self getMessageRange:str :array];
}
else {
return;
}
}
}
else {
[array addObject:message];
}
}
- (void)getUserNameRange:(NSString *)message{
NSRange rangeL = [message rangeOfString:@"@"];
NSRange rangeR = [message rangeOfString:@":"];
// NSRange rangeR1 = [message rangeOfString:@": "];
NSUInteger lenght = rangeR.location - rangeL.location;
if (lenght>100) {
return;//正常的用户名,都不会超出这个范围。用于防止用户输入了中文符号显示的错误。
}
NSRange userNameRange = NSMakeRange(0, lenght);
[self.textStorage addAttribute:NSForegroundColorAttributeName value:[UIColor orangeColor] range:userNameRange];
}
@end
ViewController中
#import "ViewController.h"
#import "ExpressionView.h"
#import "UITextView+expression.h"
@interface ViewController (){
NSString *messageStr;
NSString *messageStr2;
}
@property (weak, nonatomic) IBOutlet UITextView *inputTextView;
@property (weak, nonatomic) IBOutlet UITextView *putTextView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
ExpressionView *myView=[[ExpressionView alloc]initWithFrame:CGRectMake(50, 200, 250, 200)];
myView.backgroundColor=[UIColor redColor];
[self.view addSubview:myView];
__weak typeof (self) weakSelf = self;
[myView sendExpressModel:^(MCIExpressionModel *expressionModel) {
// messageStr=[NSString stringWithFormat:@"%@%@",self.inputTextView.text,expressionModel];
messageStr=[NSString stringWithFormat:@"%@[睡@2x]",weakSelf.inputTextView.text];
messageStr2=[NSString stringWithFormat:@"%@[睡]",weakSelf.inputTextView.text];
weakSelf.inputTextView.text=messageStr2;
NSLog(@".......");
}];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)sendMessageClincked:(UIButton *)sender {
[self.putTextView setCommentTextView:messageStr];
}
@end
最后那个表情是从微信包里取得,你可以下一个pp租手下载一个微信安装包,如图这样
屏幕快照 2016-06-15 下午8.52.55.png
然后点击右键压缩安装包,如图
屏幕快照 2016-06-16 下午8.59.47.png
显示包内容就ok了