首页 >Swift

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

2016-10-18 08:48 编辑: 不灭的小灯灯 分类:Swift 来源:iOS巍的简书

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


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

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

2240549-a16f934366ab331f.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);

2240549-e398afee767ae40f.png

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


文章转自 iOS巍的简书
搜索CocoaChina微信公众号:CocoaChina
微信扫一扫
订阅每日移动开发及APP推广热点资讯
公众号:
CocoaChina
我要投稿   收藏文章
上一篇:21个高质量的Swift开源iOS App
下一篇:一篇文章学会页面传值的10种方法(上)
我来说两句
发表评论
您还没有登录!请登录注册
所有评论(0

综合评论

相关帖子

sina weixin mail 回到顶部