在网上搜索图文混排的帖子,有好多。。大多用的第三框架,但是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 . text as 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()
}