仿微信表情输入

哇哦,好久没有写过博客了,前段时间太忙了。最近项目需求,要实现一个类似微信的的表情输入,于是把微信的表情扒拉出来,实现了一把。可以从这里下载源码。看起来表情输入没有多少东西,不外乎就是用NSTextAttachment来实现图文混排,结果在实现的过程中遇到了很多小问题,接下来会一一介绍遇到过的坑。先上一张效果图:

效果

一、实现表情选择View(WKExpressionView)

具体的实现就不细说了,主要功能就是点击表情时,将对应表情的图片名称通知给delegate。

二、实现表情textView(WKExpressionTextView)

WKExpressionTextView继承自UITextView, 提供 
- (void)setExpressionWithImageName:(NSString *)imageName fontSize:(CGFloat)fontSize方法,用于根据图片插入表情。 具体实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//富文本
     WKExpressionTextAttachment *attachment = [[WKExpressionTextAttachment alloc] initWithData: nil ofType: nil ];
     UIImage *image = [UIImage imageNamed:imageName];
     attachment.image = image;
     attachment.text = [WKExpressionTool getExpressionStringWithImageName:imageName];
     attachment.bounds = CGRectMake(0, 0, fontSize, fontSize);
     NSAttributedString *insertAttributeStr = [ NSAttributedString attributedStringWithAttachment:attachment];
     NSMutableAttributedString *resultAttrString = [[ NSMutableAttributedString alloc] initWithAttributedString: self .attributedText];
 
     //在当前编辑位置插入字符串
     [resultAttrString insertAttributedString:insertAttributeStr atIndex: self .selectedRange.location];
 
     NSRange tempRange = self .selectedRange;
 
     self .attributedText = resultAttrString;
 
     self .selectedRange = NSMakeRange (tempRange.location + 1, 0);
 
     [ self .textStorage addAttributes:@{ NSFontAttributeName : [UIFont systemFontOfSize:_defaultFontSize]} range: NSMakeRange (0, self .attributedText.length)];
 
     [ self scrollRangeToVisible: self .selectedRange];
 
     [ self textChanged];

 其中WKExpressionTextAttachment继承自NSTextAttachment, 并新增text字段,为了保存表情对应的文本,用于复制粘贴操作。

1
2
3
4
5
@interface WKExpressionTextAttachment : NSTextAttachment
 
@property ( nonatomic , copy ) NSString *text;
 
@end

 WKExpressionTool的提供将普通字符串转换为富文本的方法,主要用于复制时生成表情。 
主要方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
+ ( NSAttributedString *)generateAttributeStringWithOriginalString:( NSString *)originalString fontSize:(CGFloat)fontSize
{
     NSError *error = NULL ;
     NSMutableAttributedString *resultAttrString = [[ NSMutableAttributedString alloc] initWithString:originalString];
     NSRegularExpression *regex = [ NSRegularExpression regularExpressionWithPattern:@ "\\[[a-zA-Z0-9\u4e00-\u9fa5]{1,}\\]" options: NSRegularExpressionAllowCommentsAndWhitespace error:&error];
 
 
     NSArray *results = [regex matchesInString:originalString options: NSMatchingReportCompletion range: NSMakeRange (0, originalString.length)];
     if (results) {
         for ( NSTextCheckingResult *result in results.reverseObjectEnumerator) {
             NSRange resultRange = [result rangeAtIndex:0];
 
             NSString *stringResult = [originalString substringWithRange:resultRange];
 
             NSLog (@ "%s %@\n" , __FUNCTION__, stringResult);
 
             NSAttributedString *expressionAttrString = [ self getAttributeStringWithExpressionString:stringResult fontSize:fontSize];
 
             [resultAttrString replaceCharactersInRange:resultRange withAttributedString:expressionAttrString];
         }
 
     }
     return resultAttrString;
}

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
  *  通过表情生成富文本
  *
  *  @param expressionString 表情名
  *  @param fontSize         对应字体大小
  *
  *  @return 富文本
  */
+ ( NSAttributedString *)getAttributeStringWithExpressionString:( NSString *)expressionString fontSize:(CGFloat)fontSize
{
 
     NSString *imageName = [ self getExpressionStringWithImageName:expressionString];
 
     WKExpressionTextAttachment *attachment = [[WKExpressionTextAttachment alloc] initWithData: nil ofType: nil ];
     UIImage *image = [UIImage imageNamed:imageName];
     attachment.image = image;
     attachment.text = [WKExpressionTool getExpressionStringWithImageName:imageName];
     attachment.bounds = CGRectMake(0, 0, fontSize, fontSize);
     NSAttributedString *appendAttributeStr = [ NSAttributedString attributedStringWithAttachment:attachment];
 
     return appendAttributeStr;
 
}

 

至此,基本功能实现完成。 接下来说说遇到的小问题

  • 编辑是应该对应selectedRange
  • 复制粘贴操作需要重新实现
  • textView在插入NSTextAttachment后,会默认把font的size修改为12,需要记录默认的size

对应selectedRange操作

具体的操作查看源码

重新实现copy、cut方法

进行复制、粘贴操作会发现,不能对图片进行复制,所以需要自己重写copy、cut方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- ( void ) copy :( id )sender
{
     NSAttributedString *selectedString = [ self .attributedText attributedSubstringFromRange: self .selectedRange];
     NSString *copyString = [ self parseAttributeTextToNormalString:selectedString];
 
     UIPasteboard *pboard = [UIPasteboard generalPasteboard];
     if (copyString.length != 0) {
         pboard.string = copyString;
     }
}
 
- ( void )cut:( id )sender
{
     [ self copy :sender];
 
     NSMutableAttributedString *originalString = [[ NSMutableAttributedString alloc] initWithAttributedString: self .attributedText];
     [originalString deleteCharactersInRange: self .selectedRange];
     self .attributedText = originalString;
 
     NSLog (@ "--%@" , NSStringFromRange ( self .selectedRange));
     [ self textChanged];
}

 

记录默认font的size

利用实例变量defaultFontSize,在WKExpressionTextView实例化时记录self.font.pointSize,以后需要取font的size时,直接取defaultFontSize

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@interface WKExpressionTextView : UITextView
 
@property ( nonatomic , assign) CGFloat defaultFontSize;
 
@end
 
@implementation WKExpressionTextView
 
{
     CGFloat _defaultFontSize;
}
 
- ( void )awakeFromNib
{
     [ self setup];
}
 
- (instancetype)initWithFrame:(CGRect)frame
{
     self = [ super initWithFrame:frame];
     if ( self ) {
         [ self setup];
     }
     return self ;
}
 
- ( void )setup
{
     [[ NSNotificationCenter defaultCenter] addObserver: self selector: @selector (textChange:) name:UITextViewTextDidChangeNotification object: self ];
 
     _defaultFontSize = self .font.pointSize;
 
     self .delegate = self ;
}
复制代码
src="http://player.youku.com/embed/XNzkxMTc3OTM2" allowfullscreen="" frameborder="0" height="498" width="510">
src="http://player.youku.com/embed/XNzkxMTc3OTM2" allowfullscreen="" frameborder="0" height="498" width="510">
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值