iOS聊天开发之富文本界面

延续之前的文章,本篇关于即时聊天界面的开发技巧。首先需要参考别人的产品,最具有参考性的应该是微信App了,它可以发送文字、表情、语音、图片等,这里讨论的是文字与表情混排的常见消息类型。使用到的是YYText

YYText对很多iOS开发者并不陌生,因为在处理图文混排问题上,经常会用上它,而且API也算容易上手。所以先看将讨论呈现的效果图:

Chat VC

其实上面主要有两个知识点,一个是是图像的区域拉伸,一个是富文本追加图片,然后使用YYTextLayout去计算文字的layout布局,添加Label的点击和长按事件,监听调用选择、全选、复制、粘贴的气泡。
使用到的图片资源:

assets

实现的代码如下,详细注释了,其实也就是参考YYText给的sample,自己修修改改就行了,另一个对话气泡就没贴出代码了,因为跟下面的代码太过相似重复。
这个只是实现了效果图,但是没有放到UITableView里面去复用,算是个小TODO吧,后面可以加个聊天头像,放到TableView上滚动试试。

- (void)messageFromOther {
    
    //创建支持拉伸的UIImage
    UIImage *chatImage = [UIImage imageNamed:@"ReceiverTextNodeBkg"];
    UIImage *resizableImage = [chatImage resizableImageWithCapInsets:UIEdgeInsetsMake(30, 28, 85, 28) resizingMode:UIImageResizingModeStretch];
    //创建聊天背景的气泡ImageView
    UIImageView *chatBg = [[UIImageView alloc] init];
    chatBg.image = resizableImage;
    [self.view addSubview:chatBg];
    
    //创建YYLabel
    YYLabel *chatLabelLeft = [[YYLabel alloc] init];
    chatLabelLeft.numberOfLines = 0;
    [self.view addSubview:chatLabelLeft];
    
    //添加点击事件
    chatLabelLeft.highlightTapAction = ^(UIView * _Nonnull containerView, NSAttributedString * _Nonnull text, NSRange range, CGRect rect) {
        NSLog(@"TapAction:\n%@\n%@\n%@\n%@", containerView, text, NSStringFromRange(range), NSStringFromCGRect(rect));
    };
    //添加长按事件
    chatLabelLeft.highlightLongPressAction = ^(UIView * _Nonnull containerView, NSAttributedString * _Nonnull text, NSRange range, CGRect rect) {
        NSLog(@"LongPressAction:\n%@\n%@\n%@\n%@", containerView, text, NSStringFromRange(range), NSStringFromCGRect(rect));
    };
    
    //聊天气泡背景随Label的layout变化而变化,气泡包裹chatLabelLeft
    [chatBg mas_makeConstraints:^(MASConstraintMaker *make) {
        make.leading.equalTo(chatLabelLeft).offset(-20);
        make.trailing.equalTo(chatLabelLeft).offset(20);
        make.top.equalTo(chatLabelLeft).offset(-10);
        make.bottom.equalTo(chatLabelLeft).offset(20);
    }];
    
    //创建富文本
    NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:@"hello🇺🇸, 我是小小小鸭子🦆!我来自马达加斯加🐶,很高兴认识你。😊🌹有什么问题欢迎向我提问,我是一个建筑工人,负责搬砖的。😄😄😄😄😄😄😄😄😄"];
    attributedText.yy_font = [UIFont systemFontOfSize:16];
    
    //富文本追加UIImage的Attachment
    UIImage *image = [UIImage imageNamed:@"hot_position"];
    NSMutableAttributedString *attachment = [NSMutableAttributedString yy_attachmentStringWithContent:image contentMode:UIViewContentModeCenter attachmentSize:image.size alignToFont:chatLabelLeft.font alignment:YYTextVerticalAlignmentCenter];
    [attributedText appendAttributedString: attachment];
    
    
    //计算富文本的layout
    CGSize size = CGSizeMake(300, CGFLOAT_MAX);
    YYTextLayout *layout = [YYTextLayout layoutWithContainerSize:size text:attributedText];
    chatLabelLeft.size = layout.textBoundingSize;
    chatLabelLeft.textLayout = layout;
    chatLabelLeft.y = 120;
    chatLabelLeft.x = 40;
    
    //增加高亮效果
    YYTextBorder *highlightBorder = [YYTextBorder borderWithFillColor:[UIColor lightGrayColor] cornerRadius:0];
    YYTextHighlight *highlight = [YYTextHighlight new];
    [highlight setColor:[UIColor whiteColor]];
    [highlight setBackgroundBorder:highlightBorder];
    [attributedText yy_setTextHighlight:highlight range:NSMakeRange(0, attributedText.length)];
    
    //富文本绑定到YYLabel上
    chatLabelLeft.attributedText = attributedText;
}

对图片拉伸区域的界定是通过UIEdgeInsetsMake(30, 28, 85, 28)实现的,四个数字依次对应图片的上左下右四个像素距离,好像之前写过一篇关于拉伸的文章,不知道是不是在之前的博客上,待会去找找,找到了就移过来...找到了,点我跳转
其实上面的代码还很不完美,因为图文混排的追加不能用这样的方式去创建追加,那如果需要有很多的hot_position等图片需要追加的话,恐怕会成为灾难。采用的是YYText所提供的另一种方法,其实官网也有,我这边偷过来贴上:

// 1. 创建一个解析器
	
// 内置简单的表情解析
YYTextSimpleEmoticonParser *parser = [YYTextSimpleEmoticonParser new];
NSMutableDictionary *mapper = [NSMutableDictionary new];
mapper[@":smile:"] = [UIImage imageNamed:@"smile.png"];
mapper[@":cool:"] = [UIImage imageNamed:@"cool.png"];
mapper[@":cry:"] = [UIImage imageNamed:@"cry.png"];
mapper[@":wink:"] = [UIImage imageNamed:@"wink.png"];
parser.emoticonMapper = mapper;
	
// 内置简单的 markdown 解析
YYTextSimpleMarkdownParser *parser = [YYTextSimpleMarkdownParser new];
[parser setColorWithDarkTheme];
    
// 实现 `YYTextParser` 协议的自定义解析器
MyCustomParser *parser = ... 
    
// 2. 把解析器添加到 YYLabel 或 YYTextView
YYLabel *label = ...
label.textParser = parser;

如果你不想用它赠送的解析器,可以自己写一个解析器,利用正则表达式去匹配特定的字符串,然后读取替换成图像表情。

posted @ 2018-05-09 17:12  Mr轨迹  阅读(981)  评论(0编辑  收藏  举报