Swift3.0图文混排进阶(一)数据准备

基于Swift写一个小轮子,使用微博的表情素材,简单友好的生成属性文本写下此篇,记录其中的知识点


一、从磁盘加载表情数据(数据准备)

画了个记载数据的思维图,可以对照着下面的代码理一下思路:


Swift3.0图文混排进阶(一)数据准备_第1张图片
加载bundle数据.png

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); 
Swift3.0图文混排进阶(一)数据准备_第2张图片
屏幕快照 2016-10-17 上午12.30.02.png

最后奉上demo地址:https://github.com/iosyaowei/YWFace-Demo
可以关注下,会持续更新。。。

你可能感兴趣的:(Swift3.0图文混排进阶(一)数据准备)