iOS 图文混排
图文混排,早已成为很多APP必不可少的功能,即一段文字里加入图片,特别是聊天和评论的界面,文字加入表情图片。
那么,如何实现这一功能呢?如今要实现这一功能的框架颇多,但了解实现原理还是有一定的必要性,最近整理笔记,就记录如下,也希望对这方面不太了解的童鞋有所帮助。
思路
- 实现图文混排,首先要明确用什么控件展示文字和图片,能够展示多行文字的有两个控件,
UILabel
和UITextView
- 表情键盘是系统表情键盘还是自定义表情键盘,系统表情是emoji表情,是十六进制字符串,不需要做特别处理,就能够展示
- 如果是自定义表情键盘,那么一般大都是小图标,那么就应该有图片名,有的应该还有对应的表情名,如:[呵呵]
- 对于自定义表情的话,那么一般情况下,我使用属性字符串来修改局部文字颜色,用正则表达式获取表情名,再转为属性字符串,设置大小,最后展示在控件上
- 当然属性字符串,有的叫富文本
实现
一般情况下,对于这种功能,有太多地方需要用到,我会进行封装,可以给NSString写分类,也可以专门创建属性字符串管理者来实现:
class TCAttibuteStingManager {
}
extension TCAttibuteStingManager {
class func greateNormalAttibutesString(_ username: String, _ message: String) -> NSAttributedString {
let str = username + message
// 创建NSMutableAttributedString
let attrStr = NSMutableAttributedString(string: str)
// 修改名字颜色
let nameRange = NSRange(location: 0, length: username.characters.count)
attrStr.setAttributes([NSForegroundColorAttributeName: UIColor.orange], range: nameRange)
return attrStr
}
}
以上只是对普通字符串转为属性字符串的函数,就可以实现名字高亮,其他文字普通状态的样式,图文混排只是更进一步而已,如下:
class func greateChatMessage(_ username: String, _ message: String, font: UIFont) -> NSAttributedString {
let str = username + ":" + message
let attrStr = NSMutableAttributedString(string: str)
let nameRange = NSRange(location: 0, length: username.characters.count)
attrStr.setAttributes([NSForegroundColorAttributeName: UIColor.orange], range: nameRange)
// 字符串,如:i [爱心] you [色] girl [抱抱]!
// []为图片字符串,需要替换为图片
// 图文混排,使用正则表达式
// .*?
// 匹配规则
let pattern = "\\[.*?\\]"
guard let reg = try? NSRegularExpression(pattern: pattern, options: .caseInsensitive) else {
return attrStr
}
// 匹配结果
let range = NSRange(location: 0, length: str.characters.count)
let results = reg.matches(in: str, options: [], range: range)
// 遍历匹配结果
// 倒序遍历
for i in (0..<results.count).reversed() {
let result = results[i]
let imageName = (str as NSString).substring(with: result.range)
guard let image = UIImage(named: imageName) else {
continue
}
// 创建NSTextAttachment
let attachment = NSTextAttachment()
attachment.image = image
attachment.bounds = CGRect(x: 0, y: -4, width: font.lineHeight, height: font.lineHeight)
// 创建图片NSAttributedString
let imageAttrStr = NSAttributedString(attachment: attachment)
// 替换
attrStr.replaceCharacters(in: result.range, with: imageAttrStr)
}
return attrStr
}
由上面可知,核心代买是for循环内部,创建NSTextAttachment
,然后根据匹配结果,把NSTextAttachment
对象转为属性字符串!如此,一个简单的图文混排就搞定了。
还有一种图文混排,就是需要下载图片,比如聊天记录,给主播送礼物消息等等,代码如下:
class func createImageMessage(_ userName: String, _ imageName: String, _ imageUrl: String, font: UIFont) -> NSAttributedString {
let str = userName + ":xxxxxx" + imageName
let attrStr = NSMutableAttributedString(string: str)
let nameRange = NSRange(location: 0, length: userName.characters.count)
attrStr.setAttributes([NSForegroundColorAttributeName: UIColor.orange], range: nameRange)
let imageNameRange = (imageName as NSString).range(of: imageName)
attrStr.setAttributes([NSForegroundColorAttributeName: UIColor.orange], range: imageNameRange)
// 下载图片
guard let image = KingfisherManager.shared.cache.retrieveImageInMemoryCache(forKey: imageUrl) else {
return attrStr
}
let attachment = NSTextAttachment()
attachment.image = image
attachment.bounds = CGRect(x: 0, y: -4, width: font.lineHeight, height: font.lineHeight)
let imageAttr = NSAttributedString(attachment: attachment)
// 拼接
attrStr.append(imageAttr)
return attrStr
}
以上3个函数,直接拷贝就可使用,至于其他如链接高亮等等,还需要其他匹配规则,童鞋们可再做扩展。