哇哦,好久没有写过博客了,前段时间太忙了。最近项目需求,要实现一个类似微信的的表情输入,于是把微信的表情扒拉出来,实现了一把。可以从这里下载源码。看起来表情输入没有多少东西,不外乎就是用NSTextAttachment来实现图文混排,结果在实现的过程中遇到了很多小问题,接下来会一一介绍遇到过的坑。先上一张效果图:
具体的实现就不细说了,主要功能就是点击表情时,将对应表情的图片名称通知给delegate。
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操作
具体的操作查看源码
重新实现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
;
}
|