当下发状态和发评论已经渐渐成为不少软件的必备功能,这两者功能基本类似。但是有普通编辑和高级编辑之分,普通的评论只能发文本,一旦可以发送表情(非emoji表情)就需要用到图文混排。并且系统只能提供emoji表情,要用到其他自定义表情需要自行添加表情键盘。

因为表情键盘和图文混排写在一起太长了分为两期。本期以新浪微博的发微博页面为例,整理添加表情键盘的步骤,下期会总结自己在编写图文混排中遇到的种种问题和解决方案。基本的页面类似于这样,有部分细节没做不过也无关大雅了。编写的语言用的是swift

我表情键盘的做法是,在发布微博控制器页面底部添加一个toolbar 然后底部的约束拖一根线到控制器里,可以根据监听键盘的弹出动态修改。

下面的表情键盘是新建一个xib或者storyboard 建一个普通控制器,上面放collectionView,下面放一个view或者toolbar显示表情的种类。

collectionViewCell内部放一个imageView 和 一个Label。因为emoji表情是需要用label显示的。

下图是两个设计界面

左边的撰写微博控制器和上面的效果截图有些不同。因为设置了导航栏的颜色主题是黄色。里面灰色的placeholder请发布微博是用代码添加的设置为textView的子控件。上面的设置可以自行脑补在此不作过多赘述了,本文主要是总结表情键盘和图文混排

右边的表情键盘控制器也是可以清楚地看到cell里有imgView和label

这里记得要在撰写微博控制器里设置,点击小圆脸就设置第一响应者,并且把弹出键盘的inputView设置成我们自定义的这个表情键盘控制器。

然后就是里面cell的流水布局,把控制器里的布局拖到控制器中修改

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))
    }

在撰写微博控制器里,接收到数据模型后能打印出来就证明前面的表情键盘都做好了。

你可能感兴趣的内容
0条评论

dexcoder

这家伙太懒了 <( ̄ ﹌  ̄)>
Owner