自定义表情键盘
表情包含:默认、Emoji和浪小花
提供方式:bundle文件
框架结构:
分析:
目前有一维数组:
- 默认表情 一共108个
- emoji表情 一共80个
- 浪小花 一共40个
把以上的一维数组转成二维数组
表情分类: 每一个一维数组中包含元素个数: 索引:
默认表情 [20 20 20 20 20 8] 0 - 19 , 20 - 39 ..... ,100- 107
emoji表情 [20 20 20 20 ] 0 - 19 , 20 - 39 , 40 -59
浪小花 [20 20] 0 - 19 , 20 - 39
代码实现:
① 因为表情信息会多次使用,所以提供一个全局访问点,便于使用
//全局访问点(单例)
static let sharedTool: JSEmoticonTool = JSEmoticonTool()
② 获取表情包bundle路径
// 懒加载获取Bundle
lazy var emoticonBundle: NSBundle = {
// 获取bundle路径
let path = NSBundle.mainBundle().pathForResource("Emoticons.bundle", ofType: nil)!
// 获取bundle
let bundle = NSBundle(path: path)!
// 返回bundle
return bundle
}()
③ 提供一个公共方法,从bundle中的plist文件提取出一维数组
// MARK: - 读取plist文件中的数组,转成模型一维数组
private func getEmoticons(fileName: String) -> [JSEmoticonModel] {
///...Classes/Compose/View/Emoticon/Emoticons.bundle/Contents/Resources/emoji/info.plist
// 读取plist文件中的数组转成模型一维数组
// 文件路径
let file = emoticonBundle.pathForResource("\(fileName)/info.plist", ofType: nil)!
// plist文件转数组
let array = NSArray(contentsOfFile: file)!
// 创建可变临时数组
var tmpArr: [JSEmoticonModel] = [JSEmoticonModel]()
// 遍历Array
for dict in array {
// KVC 字典转模型
let element = JSEmoticonModel(dict: dict as! [String: AnyObject])
// 保存模型
tmpArr.append(element)
}
// 返回存放模型的一维数组
return tmpArr
}
补充
- pathForResource获取到的路径并不完整,只能获取到bundle的Resources文件夹,所以进行了拼接,得到完整的路径
- 并且bundle中存放的图片无法直接通过转模型后的图片名直接使用,需要根据导入的bundle文件拼接完整路径才可以
// 图片表情
// 从模型中获取补充的路径名
let path = emoticonModel.path ?? ""
// 从模型中获取图片的名称
let png = emoticonModel.png ?? ""
// 拼接图片的全路径
let name = path + png
let image = UIImage(named: name, inBundle: JSEmoticonTool.sharedTool.emoticonBundle, compatibleWithTraitCollection: nil)
button.setImage(image, forState: UIControlState.Normal)
④ 根据公共方法懒加载表情数据,得到的是一维数组
// default 表情 : 一维数组
lazy var defaultEmoticons: [JSEmoticonModel] = {
return self.getEmoticons("default/")
}()
// emoji 表情 : 一维数组
lazy var emojiEmoticons: [JSEmoticonModel] = {
return self.getEmoticons("emoji/")
}()
// 浪小花 表情 : 一维数组
lazy var lxhEmoticons: [JSEmoticonModel] = {
return self.getEmoticons("lxh/")
}()
⑤ 根据表情键盘布局规则,将一维数组转二维数组
// 显示列数
let EmoticonMaxCol = 7
// 显示行数
let EmoticonMaxRow = 3
// 每页显示的个数
let EmoticonMaxCount = EmoticonMaxCol * EmoticonMaxRow - 1
每一页显示固定的表情个数,所以需要将一维数组重新按照每页显示表情个数重新分组
遍历每一个一维数组,将一维数组转成二维数组
// MARK: - 一维数组转二维数组
func getEmoticonsGroup(emoticons: [JSEmoticonModel]) -> [[JSEmoticonModel]] {
// 计算页数
let pageCount = (emoticons.count + EmoticonMaxCount - 1) / EmoticonMaxCount
// 创建一个临时的可变的二维数组
var tempArray:[[JSEmoticonModel]] = [[JSEmoticonModel]]()
// 遍历一维数组(正序) 截取一维数组
for i in 0..<pageCount {
// 位置和长度
let loc = EmoticonMaxCount * i
var len = EmoticonMaxCount
// 避免数组越界
if loc + len > emoticons.count {
len = emoticons.count - loc
}
// 截取范围
let range = NSMakeRange(loc, len)
// 数组的截取
let arr = (emoticons as NSArray).subarrayWithRange(range) as! [JSEmoticonModel]
// 保存一维数组
tempArray.append(arr)
}
// 返回二维数组
return tempArray
}
⑥ 最后将得到的二维数组合成为三维数组
// 表情 : 三维数组
lazy var allEmoticons: [[[JSEmoticonModel]]] = {
return [
self.getEmoticonsGroup(self.defaultEmoticons),
self.getEmoticonsGroup(self.emojiEmoticons),
self.getEmoticonsGroup(self.lxhEmoticons)
]
}()
这样,再通过CollectionView分配数据时:
三维数组的长度 --> CollectionView --> NumberOfSection
二维数组的长度 --> CollectionView --> NumberOfItemInSection
一维数组的元素 --> CollectionView --> Cell所需数据
// 数据源方法
extension JSEmojiconPageView: UICollectionViewDataSource {
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return JSEmoticonTool.sharedTool.allEmoticons.count
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return JSEmoticonTool.sharedTool.allEmoticons[section].count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(collectionViewCellId, forIndexPath: indexPath) as! JSEmojiconPageViewCell
cell.indexpath = indexPath
cell.emoticons = JSEmoticonTool.sharedTool.allEmoticons[indexPath.section][indexPath.item]
return cell
}
}