IOS开发笔记(十三)——实现IM的聊天记录,基于UITableView图文混排

中山大学数据科学与计算机学院本科生实验报告

(2019年春季学期)

课程名称IOS开发任课老师郑贵锋
年级16专业(方向)软件工程(计算机应用方向)
学号16340132姓名梁颖霖
电话13680473185Emaildic0k@qq.com
开始日期2019/6/9完成日期2019/6/12

一、实验题目

IM聊天工具

二、实现内容

  • IM聊天记录显示图片文字混排
  • 实现好友间发送图片

三、实验结果

IM聊天记录显示图片文字混排

由于在实现了文字纯文本的好友聊天功能后,我们添加了发送图片这一功能,可以在好友记录中显示出来。这一来需要我改变之前显示聊天记录的TableView的显示,经过一些搜索,找到了实现这一需求叫做实现图文混排。有以下一些思路来实现图文混排:

  • UITextView结合NSAttributeString实现图文混排编辑,这个方案可以在网上找到对应的开源代码,比如 SimpleWord 的实现就是使用这种方式,不过缺点是图片不能有交互,比如说在图片上添加进度条,添加上传失败提示,图片点击事件处理等等都不行,如果没有这种需求那么可以选择这种方案。
  • 使用WebView通过js和原生的交互实现,比如 WordPress-EditorRichTextDemo ,主要的问题就是性能不够好,还有需要你懂得前端知识才能上手。
  • 使用CoreText或者TextKit,这种也有实现方案的开源代码,比如说这个 YYText ,这个很有名气,不过他使用的图片插入编辑图片的位置是固定的,文字是围绕着图片,所以这种不符合我的要求,如果要使用这种方案,那修改的地方有很多,并且CoreText/TextKit使用是有一定的门槛的。
  • 使用UITableView结合UITextView的假实现,主要的思路是每个Cell是一个文字输入的UITextView或者是用于显示图片使用的UITextView,图片显示之所以是选择UITextView是因为图片位置需要有输入光标,所以使用UITextView结合NSAttributeString的方式正好可以实现这个功能。图片和文字混排也就是显示图片的Cell和显示文字的Cell混排就可以实现了,主要的工作量是处理光标位置输入以及处理光标位置删除。

而我这里刚好也适用的是第四种方法,仅需改变UITableView里面的TextView变成富文本的形式,即使用UITextView结合NSAttributeString的方式正好可以实现这个功能。

1

以上参见博客

iOS使用UITableView实现的富文本编辑器

除去这个方法,这里还有使用TextKit实现图文混排

  1. 拼接string
/*!
 *  插入表情
 *
 *  @param rangeArray  所要插入表情的位置  每个元素包括(loc)
 *  @param facesArray  要插入的表情的信息  每个model包括(id imageName)
 *  @param pStr        原始的字符串
 *  @param sourceArray 表情包
 *
 *  @return 拼接好的字符串
 */
+ (NSMutableAttributedString *)setupEmojiByRangeArray:(NSArray *)rangeArray facesArray:(NSArray *)facesArray plainStr:(NSAttributedString *)pStr sourceArray:(NSArray *)sourceArray {
    NSMutableAttributedString * mutStr = [pStr mutableCopy];
    __block int offset = 0;
    //每次加过一个表情后 字符串会变长 这个变量会记录已经增加的长度,不然插入的位置会错位的
    if(rangeArray.count == facesArray.count) { 
        // 看看要插入的位置的数量 是不是和要插入的表情数量一致
        [facesArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
            // 数组的枚举
            for(FaceModel * fm in sourceArray){
                // 这个在不在表情包里面
                if(fm.id == [obj[@"ID"]intValue]) {
                    UIImage * image1 = [UIImage imageNamed:fm.imageName];
                    NSTextAttachment * attachment1 = [[NSTextAttachment alloc] init];
                    //这就是要插入的对象
                    attachment1.bounds = CGRectMake(0, -3, 20, 20);
                    // 插入的表情的大小
                    attachment1.image = image1;
                    NSAttributedString * attachStr1 = [NSAttributedString attributedStringWithAttachment:attachment1];
                    // 把要插入的对象转为string
                    NSDictionary * dic = [rangeArray objectAtIndex:idx];
                    // 看看插入哪个位置
                    [mutStr insertAttributedString:attachStr1 atIndex:offset+[dic[@"loc"]intValue]];
                    offset += (int)attachStr1.length;
                    // 插入结束要计算一下偏移量
                }
            }
        }];
    }
    //    //添加链接
    //    NSURL * url = [NSURL URLWithString:@"http://www.baidu.com"];
    //    [mutStr addAttribute:NSLinkAttributeName value:url range:NSMakeRange(loc, length)];
    //    mainText.attributedText = [mutStr copy];

    return mutts;// 返回处理好的字符串
}

这个是IM的必要需求了。通过NSTextAttachment的使用,我们可以插入表情的image了。因为我这个是批量处理,所以我插入规格一致的表情。同理,我们可以插入一张图片,这就实现了图文混排了。

  1. 计算NSMutableAttributedString的Rect
// 字体大小
UIFont *font =[UIFont systemFontOfSize:14]// 段落设置
    NSMutableParagraphStyle *p = [[NSMutableParagraphStyle alloc]init];
p.lineBreakMode = NSLineBreakByCharWrapping;
p.lineSpacing = 0.1f;
p.paragraphSpacing = 0.1f;
p.alignment = NSTextAlignmentLeft;
// 设置NSAttributedString 的样式
NSAttributedString * str = [[NSAttributedString alloc]initWithString:rString attributes:@{NSFontAttributeName:font,NSParagraphStyleAttributeName:p}];
// 计算Rect
// w代表你想要的宽度  h代表你的字符串最大支持的高度
CGRect rect = [sstr boundingRectWithSize:CGSizeMake(w,h) options:NSStringDrawingUsesFontLeading|NSStringDrawingUsesLineFragmentOrigin context:nil];

最后,依靠计算出来的rect 我们就知道要怎么设置cell的高度了。再把这个string放到一个textView里面,textvView放到cell上,大功告成。

使用UITableView的实现细节
  1. Cell中添加UITextView,文字输入换行或者超过一行Cell高度自动伸缩处理
  2. Cell中添加UITextView显示图片的处理
  3. 光标处删除和添加图片的处理,换行的处理

前面第一点已经由我的组员完成了,所以我这里仅需要关注如何显示图片即可。

NSAttributedString结合NSTextAttachment就行了

/**
 显示图片的属性文字
 */
- (NSAttributedString*)attrStringWithContainerWidth:(NSInteger)containerWidth {
    if (!_attrString) {
        CGFloat showImageWidth = containerWidth - MMEditConfig.editAreaLeftPadding - MMEditConfig.editAreaRightPadding - MMEditConfig.imageDeltaWidth;
        NSTextAttachment *textAttachment = [[NSTextAttachment alloc] init];
        CGRect rect = CGRectZero;
        rect.size.width = showImageWidth;
        rect.size.height = showImageWidth * self.image.size.height / self.image.size.width;
        textAttachment.bounds = rect;
        textAttachment.image = self.image;
        
        NSAttributedString *attachmentString = [NSAttributedString attributedStringWithAttachment:textAttachment];
        NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:@""];
        [attributedString insertAttributedString:attachmentString atIndex:0];
        _attrString = attributedString;
        
        // 设置Size
        CGRect tmpImageFrame = rect;
        tmpImageFrame.size.height += MMEditConfig.editAreaTopPadding + MMEditConfig.editAreaBottomPadding;
        _imageFrame = tmpImageFrame;
    }
    return _attrString;
}
图片的获取

关于发送的图片显示是通过拉取用户聊天记录获得的,这与之前的访问服务器拉取文字记录类似,只不过现在多了图片的url而已。而对于url的处理是根据上周使用的SDWebImage来获取并且显示,这里就不重复展示。

四、实验思考及感想

本周做的东西不算太多,由于端午假期没能到实验室进行实训。再一方面,我们小组已经基本完成了需求,开始在做一些扩展的功能,我负责的就是发送图片这一功能。基本的文字发送显示架构已经可以使用,更改成图片的显示无非就是把处理文字的思路转变到处理图片上。所需要的工作包括向服务器发送图片,从服务器获取图片,将图片显示在聊天记录页面上。这周我完成的是后两步的demo功能,待下周周末到实验室再将这个demo改造到我们的IM上,难度应该不大。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值