基于Swift写一个小轮子,使用微博的表情素材,简单友好的生成属性文本写下此篇,记录其中的知识点
一、从磁盘加载表情数据(数据准备)
画了个记载数据的思维图,可以对照着下面的代码理一下思路:
1.获取自定义bundle,加载plist
创建YWEmoticonManager类,一般除了类需要做模型字典转换操作的,不然都不要继承NSObject,使用单例,因为,一般项目中,很多地方都要展示表情,这样我们就可以不用每次都需要去磁盘加载数据了,构造函数 如果在init之前增加private 修饰符,可以要求调用者必须通过 shared 访问对象, OC 要重写 allocWithZone方法,然后读取emoticons.plist,如果Bundle按照默认的结构目录设定,就可以直接读取Resourse目录文件,这样我们就拿到了plist文件:
guard let path = Bundle.main.path(forResource: "HMEmoticon", ofType: "bundle"),
let bundle = Bundle(path: path),
let plistPath = bundle.path(forResource: "emoticons", ofType: "plist"),
let array = NSArray(contentsOfFile: plistPath) as? [[String:String]] else {
return
}
2.建立数据模型
模型转化使用YYModel,所以现行导入YYModel继续接下来的操作:
- 建立表情模型
///表情类型 false-图片表情/true-emoji
var type = false
/// 表情字符串,发送给服务器(节约流量)
var chs: String?
/// 表情的图片名称,用于本地图文混排
var png: String?
/// emoji 16进制编码
var code: String?
override var description: String{
return yy_modelDescription()
}
- 建立表情包模型
/// 表情包的分组名
var groupName: String?
/// 表情包目录,从目录下加载info.plist 可以创建表情模型数组
var directory: String?
/// 懒加载表情模型空数组,使用懒加载可以避免后续的解包
lazy var emoticonArr = [YWEmoticon]()
override var description: String{
return yy_modelDescription()
}
3.加载表情包数据数组
/// 表情包懒加载数组
lazy var packageArr = [YWEmoticonPackage]()
guard let path = Bundle.main.path(forResource: "HMEmoticon", ofType: "bundle"),
let bundle = Bundle(path: path),
let plistPath = bundle.path(forResource: "emoticons", ofType: "plist"),
let array = NSArray(contentsOfFile: plistPath) as? [[String:String]],
let modelArr = NSArray.yy_modelArray(with: YWEmoticonPackage.self, json: array) as? [YWEmoticonPackage] else {
return
}
//设置表情包数组 使用 += 不会再次给packetArr 分配空间, 直接追加数据
packageArr += modelArr
4.加载表情表情模型数组
在YWEmoticonPackage模型的directory属性的didSet方法中,取出directory目录中的info.plist加载表情模型数组
/// 表情包目录,从目录下加载info.plist 可以创建表情模型数组
var directory: String?{
//当设置目录时候,从目录下加载 info.plist
didSet {
guard let directory = directory,
let path = Bundle.main.path(forResource: "HMEmoticon", ofType: "bundle"),
let bundle = Bundle(path: path),
let infoPath = bundle.path(forResource: "info", ofType: "plist", inDirectory: directory),
let array = NSArray(contentsOfFile: infoPath) as? [[String: String]],
let modelArr = NSArray.yy_modelArray(with: YWEmoticon.self, json: array) as? [YWEmoticon]else {
return
}
//设置表情模型数组
emoticonArr += modelArr
}
} ```
####5.表情模型增加目录属性,图像的计算想属性,方便获取图像
/// 表情模型所在的目录
var directory: String?
/// 图片表情对用的图像
var image:UIImage?{
//判断表情类型
if type {
return nil
}
guard let directory = directory,
let png = png,
let path = Bundle.main.path(forResource: "HMEmoticon", ofType: "bundle"),
let bundle = Bundle(path:path) else {
return nil
}
return UIImage(named: "\(directory)/\(png)", in: bundle, compatibleWith: nil)
}```
6.添加表情包数组过滤表情方法
插播关于OC数组中 使用谓词过滤的数组的用法
装逼解释:谓词是OC中提供了的针对数组处理,它的作用和数据库中的查询操作操作很像,我们可以通过简单的谓词语句对数组进行查找和过滤。
extension YWEmoticonManager {
/// 根据string [爱你] 在所有的表情符号中查找对应是表情模型
///
/// - 如果找到返回表情模型
/// - 否则 返回nil
func findEmoticon(string:String?) -> YWEmoticon? {
//遍历表情包 OC中过滤数组使用[谓词] swift 更简单
for p in packageArr {
//在表情数组中过滤 string
let result = p.emoticonArr.filter({ (em) -> Bool in
return em.chs == string
})
// 判断 结果数组的数量
if result.count == 1 {
return result[0]
}
}
return nil
}
}```
####7.扩展一下闭包的三种简写方式
//方法1.在表情数组中过滤 string
// let result = p.emoticonArr.filter({ (em) -> Bool in
// return em.chs == string
// })
//方法2.尾随闭包 - 当闭包是最后一个参数,圆括号可以提前结束
// let result = p.emoticonArr.filter(){ (em) -> Bool in
// return em.chs == string
// }
//方法3.如果闭包中只有一句,并且是返回,闭包格式可以省略【闭包格式 指的是 in之前的语句】,参数省略之后,使用$0,$1依次替代
// let result = p.emoticonArr.filter(){
// return $0.chs == string
// }
//方法4.如果闭包中只有一句,并且是返回,闭包格式可以省略【闭包格式 指的是 in之前的语句】,参数省略之后,使用$0,$1依次替代,return也可以省略
let result = p.emoticonArr.filter(){ $0.chs == string} ```
8.根据当前的表情模型,生成图像的属性文本
在表情模型中,实现此方法
//根据当前的图像,生成图像的属性文本
func imageText(font:UIFont) -> NSAttributedString {
//判断图像是否存在
guard let image = image else {
return NSAttributedString(string: "")
}
//创建文本附件 -图像
let attachment = NSTextAttachment()
attachment.image = image
//lineHeight 大致和字体大小相等
let height = font.lineHeight
attachment.bounds = CGRect(x: 0, y: -4, width: height, height: height)
//返回图像属性文本
return NSAttributedString(attachment: attachment)
}
8.至此,初步的封装就做好了,我们可以测试一下
//测试直接生成表情属性文本
let emo = YWEmoticonManager.shared.findEmoticon(string: "[马到成功]")
testlabel.attributedText = emo?.imageText(font: testlabel.font);
最后奉上demo地址:https://github.com/iosyaowei/YWFace-Demo
可以关注下,会持续更新。。。