在网上搜索图文混排的帖子,有好多。。大多用的第三框架,但是swift实现图文混排的帖子还真不多,我在这里和大家一起梳理一下。希望彼此都能有所帮助,
废话不多说,进入正题:
首先我们都知道,图文混排主要是用在UITextView/ UILab / UITextFiled 等能够输入或者显现表情与文字的控件中,主要用到的属性是NSAttributeText,因此,我们基本上可以把图文混排分为三部分内容
1. 表情键盘的创建(将表情包中的表情添加到键盘上)
2. 点击表情时,表情能够与文字同时显示到输入框上
3. 可以上传到服务器,并且在前端显示出来
现在我们就开始分别总结一下这三点:
1. 表情键盘的创建
首先是表情源的获取,基本上是一个NSBundle文件,里面装几个表情文件夹,我们获取到每一个图片,然后赋值到表情键盘的button上,表情键盘的实质也就是一个UICollectionView,每个cell上放了若干了button,这一部分比较简单。我们就不做过多的赘述,有兴趣的同学可以直接看代码<EmoticonView.swift>
2. 表情键盘显示到输入框
//通过点击表情按钮,发送通知,将button传递过来,里面包含了自身的表情模型
// 创建NSMutableAttributedString对象
textAttachment.bounds = CGRectMake(0, -5, (textV.font!.lineHeight), textV.font!.lineHeight)
//获取当前的光标位置
let attributeString = NSAttributedString(attachment: textAttachment)
//设置位置,替换
let range = textV.selectedRange
attributeMutableString.replaceCharactersInRange(range, withAttributedString: attributeString)
attributeMutableString.addAttributes([NSFontAttributeName: textV.font!], range: NSMakeRange(0, attributeMutableString.length))
//MARK:设置表情的大小
textV.attributedText = attributeMutableString
//让光标回到下一个位置
textV.selectedRange = NSMakeRange(range.location + 1, 0)
}
if let emoji = emoticon?.emoji {
textV.replaceRange(textV.selectedTextRange!, withText: emoji)
3. 表情文本的上传到服务器,首先我们要清楚一下,发布到服务器都必须是字符串形式,这就需要我们在上传之前,将textView的attributeText全部转化为字符串,
self.attributedText.enumerateAttributesInRange(NSMakeRange(0,self.attributedText.length), options: []) { (data, range, _) -> Void in
}else{
//将self.textV.text按照范围进行切割
print(range)
let subString = (self.textas NSString).substringWithRange(range)
publishString = publishString + subString
}
}
return publishString
最后就是从服务器获取到的有表情的text在前端的展示,这块用到了正则表达式, 里面用到了两个方法
class func getAttributeString(emoticon:HMEmoticon? ,font: UIFont) -> NSAttributedString? {
// 1. 创建一个附件对象
let attachment = HMTextAttachment()
// 1.1 拼接图片路径
guard let path = emoticon?.path,png = emoticon?.png else {
return nil
}
let imagePath = "\(path)/\(png)"
// 1.2 设置他的属性
attachment.image = UIImage(named: imagePath)
// 1.3 修改图片的bounds
// 思考表情的宽高怎么设置?
let lineHeght = font.lineHeight
attachment.bounds = CGRectMake(0,-5, lineHeght, lineHeght)
// 2. 创建一个NSAttributeString对象
let attribute = NSAttributedString(attachment: attachment)
return attribute
}
guard let text = text else {
return NSAttributedString()
}
// 定义一个 全局AttributeString
let globleAttribute = NSMutableAttributedString(string: text)
// 1. 把表情的对象HMEmotion,发送给了 HMPublishViewController
// 2. 创建了一个NSAttributeString, 拥有一个附件.NStextAttachment, image
// 3. textView的Attribute = attribute
/*
text -- 微博内容含有表情的情况有多种
1.没有表情
2.有一个表情 -> [微笑]
3.有多个表情
*/
// I [嘻嘻] U
/*
. 匹配任意字符,除了换行
() 锁定要查找的内容
* 匹配任意长度的内容
?尽量少的匹配
\\[.*?\\]
*/
// 分析正则为主
let pattern = "\\[.*?\\]"
/*
默认的try
try?
try!
*/
do {
/*
第一个参数: 正则表达式
第二个参数: 针对正则表达式的一些设置, 不要刻意去记,学一个记一个
*/
// 1. 创建正则
let regx = try NSRegularExpression(pattern: pattern, options: .DotMatchesLineSeparators)
// 2. 让正则去匹配查找
/*
第一个参数: 指定查找的字符串
第二个参数: 默认值
第三个参数: 范围
*/
let results = regx.matchesInString(text, options: [], range: NSMakeRange(0, text.characters.count))
// 3. 就是对 查找结果进行遍历
// NSTextCheckingResult
for (_,result) in results.reverse().enumerate() {
// 获取查找结果的range
let range = result.range
// 通过range来获取查找的表情字符串
let emoticonString = (text as NSString).substringWithRange(range)
// 通过表情字符串,转换成表情对象
let emoticon = HMEmoticonManager.searchEmoticon(emoticonString)
let attachment = HMTextAttachment()
attachment.emoticon = emoticon
let attribute = attachment.getAttributeString(UIFont.systemFontOfSize(16))
// 通过类方法,可以变成一行代码
let attribute2 = HMTextAttachment.getAttributeString(emoticon, font: UIFont.systemFontOfSize(16))
// globleAttribute = I U
// 进行一个替换
globleAttribute.replaceCharactersInRange(range, withAttributedString: attribute!)
}
/* 第一次打印还没有进行替换: I [嘻嘻] [嘻嘻] U{
}
~~~~~~~~~~~~~~~~~
第二次打印
I {
}{
NSAttachment = "<NSTextAttachment: 0x7fbd787f9c00>";
} [嘻嘻] U{
}
*/
// 遍历结束之后,再返回
return globleAttribute
} catch {
printLog(error)
}
return NSAttributedString()
}