IM开发iOS开发记录ios实用开发技巧

iOS开发 - 定制表情键盘

2016-12-08  本文已影响0人  VitasLiu

Preface

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

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

先看效果图:

自定制表情键盘

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

/// 切换键盘
@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分为三个模块:

数据源使用了一个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
上一篇下一篇

猜你喜欢

热点阅读