iOS开发 - 定制表情键盘

作者: VitasLiu | 来源:发表于2016-12-08 02:10 被阅读0次

    Preface

    之前分享了UITextView的图片混排, 现在轮到定制表情键盘的实现.

    表情键盘在一些IM上用的很多, 如微信, QQ, 微博等. 这个demo是基于发布微博信息里的一个功能.

    先看效果图:

    自定制表情键盘

    那么如何定制表情键盘呢?

    • 切换系统键盘, 把当前键盘收起来, 执行resignFistResponder方法
    • 设置textView的inputView属性, 更改为自定义的view
    • 弹出自定制键盘, 执行becomeFirstResponder
    /// 切换键盘
    @objc fileprivate func emotionKeyboard() {
        let emotionKeyboard = WBEmotionKeyBoard(frame: CGRect(x: 0, y: 0, width: screenWidth, height: 271))
        emotionKeyboard.backgroundColor = UIColor.white
        
        //要想切换键盘, 首先需要将当前的键盘收起来
        
        //收起键盘
        //becomeFirstResponder: 弹出键盘, 把光标定位到当前控件
        
        //收起键盘后,要迅速弹出键盘, 会产生两次动画, 让第一次动画不执行
        shouldAnimation = false
        textView.resignFirstResponder()
        shouldAnimation = true
        
        //如果是默认键盘, 弹出自定义键盘
        if isDefaultKeyboard {
            //使用自定义的键盘
            textView.inputView = emotionKeyboard
            isDefaultKeyboard = false
            //如果是自定义键盘, 弹出系统键盘
        } else {
            textView.resignFirstResponder()
            textView.inputView = nil
            isDefaultKeyboard = true
        }
        //弹出键盘
        textView.becomeFirstResponder()
    }
    

    表情键盘实现的思维导图

    表情键盘实现的思维导图

    简单分析具体实现 (UI)

    从上面的思维导图可知, 表情键盘view分为三个模块:

    • collectionView
      • 四个section(表情组)
      • 每个section有多个cell
      • 自定义cell(20个表情的button, 还有一个deleteButton)
    • pageControl
      • 用KVC的方式设置pageControl的显示样式
      • setValueForkey(_currentPageImage)
      • setValueForkey(_pageImage)
    • toolBar
      • 四个button水平分布
      • 使用UIStackView(专门做平均分布用的, ios9.0以后出来的)

    数据源使用了一个emotions.bundle, 创建一个model, 三维数组存放数据

    collectionView, pageControl 和 toolBar三者的联动

    1. 点击toolBar做任意一个button时, pageControl和collectionView的联动
    2. collectionView上的cell在向左向右滑动时, pageControl和toolBar的联动

    第一种联动实现起来比较简单, 就是在点击toolBar的一个button时, 利用代理把当前被点击的button tag值传递出去, 让pageControl的当前页为0, collectionViewCell的indexPath.section为tag值, item为0

    toolBar四个button点击触发的方法如下:

    extension WBEmotionToolBar {
        @objc fileprivate func changeEmotion (button: UIButton) {
            selectedButton?.isSelected = false
            selectedButton = button
            selectedButton?.isSelected = true
            
            delegate?.changeEmotion(index: button.tag - baseTag)
        }
    }
    

    代理方法:

    // MARK: - WBEmotionToolBarDelegate
    extension WBEmotionKeyBoard: WBEmotionToolBarDelegate {
        func changeEmotion(index: Int) {
            let indexPath = IndexPath(item: 0, section: index)
            // toolBar与emotionCollectionView的联动,顺便完成toolBar与pageControl的联动
            emtionCollectionView.scrollToItem(at: indexPath, at: UICollectionViewScrollPosition.left, animated: false)
            
            changePageContol(indexPath: indexPath)
        }
    }
    

    第二种联动实现则比较复杂, 用到一个小技巧:
    在scrollViewDidScroll方法里, 计算可见的两个cell的origin.x与当前collectionView的.contentOffset.x相减的绝对值进行比较

    offset与originx的差的绝对值越小, 则显示的区域越大

    // MARK: - UICollectionViewDelegate
    extension WBEmotionKeyBoard: UICollectionViewDelegate {
        func scrollViewDidScroll(_ scrollView: UIScrollView) {
            //获得显示的cells
            let cells = emtionCollectionView.visibleCells
            //如果屏幕上显示的cell的cell有两个
            if cells.count > 1 {
                let offset = scrollView.contentOffset.x
                //第一个cell,显示的区域
                let cellOne = cells[0]
                //offset与origin.x的绝对值
                let regionOne = abs(cellOne.frame.origin.x - offset)
                //第一个cell的indexPath
                let indexPathOne = emtionCollectionView.indexPath(for: cellOne)
                
                //第二个cell
                let cellTwo = cells[1]
                //offset与origin.x的绝对值
                let regionTwo = abs(cellTwo.frame.origin.x - offset)
                //第二个cell的indexPath
                let indexPathTwo = emtionCollectionView.indexPath(for: cellTwo)
                
                //offset与originx的差的绝对值越小, 则显示的区域越大
                if regionOne < regionTwo {
                    //使用cellOne的section
                    toolBar.index = (indexPathOne?.section)!
                    changePageContol(indexPath: indexPathOne!)
                } else {
                    //使用cellTwo的section
                    toolBar.index = (indexPathTwo?.section)!
                    changePageContol(indexPath: indexPathTwo!)
                }
            }
        }
    }
    
    定制键盘的文件目录
    有兴趣的同学可以看demo的代码实现
    My github

    相关文章

      网友评论

        本文标题:iOS开发 - 定制表情键盘

        本文链接:https://www.haomeiwen.com/subject/wqbjmttx.html