iOS开发 - 定制表情键盘

Preface

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

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

先看效果图:

iOS开发 - 定制表情键盘_第1张图片
自定制表情键盘

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

  • 切换系统键盘, 把当前键盘收起来, 执行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()
}

表情键盘实现的思维导图

iOS开发 - 定制表情键盘_第2张图片
表情键盘实现的思维导图

简单分析具体实现 (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!)
            }
        }
    }
}

iOS开发 - 定制表情键盘_第3张图片
定制键盘的文件目录

有兴趣的同学可以看demo的代码实现
My github

你可能感兴趣的:(iOS开发 - 定制表情键盘)