当下发状态和发评论已经渐渐成为不少软件的必备功能,这两者功能基本类似。但是有普通编辑和高级编辑之分,普通的评论只能发文本,一旦可以发送表情(非emoji表情)就需要用到图文混排。并且系统只能提供emoji表情,要用到其他自定义表情需要自行添加表情键盘。
因为表情键盘和图文混排写在一起太长了分为两期。本期以新浪微博的发微博页面为例,整理添加表情键盘的步骤,下期会总结自己在编写图文混排中遇到的种种问题和解决方案。基本的页面类似于这样,有部分细节没做不过也无关大雅了。编写的语言用的是swift
如果你不是在董铂然博客园看到本文,请点击查看原文。
我表情键盘的做法是,在发布微博控制器页面底部添加一个toolbar 然后底部的约束拖一根线到控制器里,可以根据监听键盘的弹出动态修改。
下面的表情键盘是新建一个xib或者storyboard 建一个普通控制器,上面放collectionView,下面放一个view或者toolbar显示表情的种类。
collectionViewCell内部放一个imageView 和 一个Label。因为emoji表情是需要用label显示的。
下图是两个设计界面
左边的撰写微博控制器和上面的效果截图有些不同。因为设置了导航栏的颜色主题是黄色。里面灰色的placeholder请发布微博是用代码添加的设置为textView的子控件。上面的设置可以自行脑补在此不作过多赘述了,本文主要是总结表情键盘和图文混排
右边的表情键盘控制器也是可以清楚地看到cell里有imgView和label
这里记得要在撰写微博控制器里设置,点击小圆脸就设置第一响应者,并且把弹出键盘的inputView设置成我们自定义的这个表情键盘控制器。
然后就是里面cell的流水布局,把控制器里的布局拖到控制器中修改
class="brush:objc;gutter:true;"> override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() setupLayout() } func setupLayout(){ let row:CGFloat = 3 let col:CGFloat = 7 let m:CGFloat = 10 let screenSize = self.collectionView.bounds.size let w = (screenSize.width - (col + 1) * m) / col layout.itemSize = CGSizeMake(w, w) layout.minimumInteritemSpacing = m layout.minimumLineSpacing = m /// 每一组之间的边距 layout.sectionInset = UIEdgeInsetsMake(m, m, m, m) layout.scrollDirection = UICollectionViewScrollDirection.Horizontal collectionView.pagingEnabled = true }
之所以写在ViewDidLayoutSubViews方法中,是为了等前面的布局完全加载好。
布局完毕后应该就是可以看到此效果。
然后就是加载表情图片,把表情图片依次填到这些方框中
表情图片的加载方法:
1.下载个新浪微博的ipa解压,在里面能够找到所有的表情包都是装在一个emticons文件夹里
2.文件夹中有个emoticons.plist文件,里面是一个数组,里面包含四个字典分别是四种表情的各项参数。和四个文件夹里装着四种表情
3.每一种表情的文件夹里还有一个info.plist文件,这个文件里是个字典包含几个自己表情参数和一个数组,里面装的是本类别的所有表情
4.这里面的参数目测应该就能看懂分别是干什么的 如图
5.这里加载表情图片时要注意不能直接使用第三方框架字典转模型,因为字典转模型之后的模型数组内值都是连续的,但是每页的右下角还需要添加一个删除按钮,所以产生矛盾
6.所以加载表情图片的基本思路是,手写方法一层一层加载,先把emoticons.plist转模型,再通过里面的path可以取到每一个info.plist再转模型。
7.然后info.plist中有一个数组里装着所有的表情,每一个表情又是一个字典再给他转模型。并设置个模型数组
8.前面设置collectionView的布局是3*7,这里就设置collectionView的Section每组21个,除去一个删除按钮正好是每页20个表情。
9.把模型和模型数组整理好,该addObject的就addObject。
最后在数据源方法中加载:
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int { /// 返回有几种表情 return emoticonSection?.count ?? 0 } func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { /// 返回每个种类中的表情数量 return emoticonSection![section].emoticons.count } func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCellWithReuseIdentifier("EmoticonsCell", forIndexPath: indexPath) as! EmoticonCell /// 属性赋值 cell.emoticon = emoticonSection![indexPath.section].emoticons[indexPath.item] return cell }
至于cellForItem里的属性赋值,是在自定义的EmoticonCell里设置didSet判断模型的种类(是否是emoji表情)再完成数据分发
/// 自定义表情cell class EmoticonCell: UICollectionViewCell { @IBOutlet weak var iconView: UIImageView! @IBOutlet weak var emojiLabel: UILabel! var emoticon: Emoticon? { /// 赋值完成后调用 didSet { if let path = emoticon?.imagePath { iconView.image = UIImage(contentsOfFile: path) } else { iconView.image = nil } emojiLabel.text = emoticon?.emoji // 是否是删除按钮 if emoticon!.isDeleteButton { iconView.image = UIImage(named: "compose_emotion_delete_highlighted") } } } }
之后表情键盘就可以如图的显示了。
然后就是监听每个按钮表情的点击事件。这里需要用到代理。
定义一个协议协议里有个方法点击时把自己(表情控制器)和点中的表情模型传过去
再在collectioView的代理方法中设置didSelected触发
协议:
protocol EmoticonsViewControllerDelegate: NSObjectProtocol { /// 选中了某一个表情 func emoticonsViewControllerDidSelectEmoticon(vc:SXEmoticonsViewController, emoticon: Emoticon) }
代理方法:
/// 根据 indexPath 返回表情数据 func emoticon(indexPath: NSIndexPath) -> Emoticon { return emoticonSection![indexPath.section].emoticons[indexPath.item] } /// cell 被选中 func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) { // 使用 ? 不需要判断代理是否实现方法 delegate?.emoticonsViewControllerDidSelectEmoticon(self, emoticon: emoticon(indexPath)) }
在撰写微博控制器里,接收到数据模型后能打印出来就证明前面的表情键盘都做好了。
如果你不是在董铂然博客园看到本文,请点击查看原文。
正在整理图文混排,有兴趣的可以关注