iOS開發(fā) - 定制表情鍵盤

Preface

之前分享了UITextView的圖片混排, 現(xiàn)在輪到定制表情鍵盤的實(shí)現(xiàn).

表情鍵盤在一些IM上用的很多, 如微信, QQ, 微博等. 這個(gè)demo是基于發(fā)布微博信息里的一個(gè)功能.

先看效果圖:

自定制表情鍵盤

那么如何定制表情鍵盤呢?

  • 切換系統(tǒng)鍵盤, 把當(dāng)前鍵盤收起來, 執(zhí)行resignFistResponder方法
  • 設(shè)置textView的inputView屬性, 更改為自定義的view
  • 彈出自定制鍵盤, 執(zhí)行becomeFirstResponder
/// 切換鍵盤
@objc fileprivate func emotionKeyboard() {
    let emotionKeyboard = WBEmotionKeyBoard(frame: CGRect(x: 0, y: 0, width: screenWidth, height: 271))
    emotionKeyboard.backgroundColor = UIColor.white
    
    //要想切換鍵盤, 首先需要將當(dāng)前的鍵盤收起來
    
    //收起鍵盤
    //becomeFirstResponder: 彈出鍵盤, 把光標(biāo)定位到當(dāng)前控件
    
    //收起鍵盤后,要迅速彈出鍵盤, 會(huì)產(chǎn)生兩次動(dòng)畫, 讓第一次動(dòng)畫不執(zhí)行
    shouldAnimation = false
    textView.resignFirstResponder()
    shouldAnimation = true
    
    //如果是默認(rèn)鍵盤, 彈出自定義鍵盤
    if isDefaultKeyboard {
        //使用自定義的鍵盤
        textView.inputView = emotionKeyboard
        isDefaultKeyboard = false
        //如果是自定義鍵盤, 彈出系統(tǒng)鍵盤
    } else {
        textView.resignFirstResponder()
        textView.inputView = nil
        isDefaultKeyboard = true
    }
    //彈出鍵盤
    textView.becomeFirstResponder()
}

表情鍵盤實(shí)現(xiàn)的思維導(dǎo)圖

表情鍵盤實(shí)現(xiàn)的思維導(dǎo)圖

簡單分析具體實(shí)現(xiàn) (UI)

從上面的思維導(dǎo)圖可知, 表情鍵盤view分為三個(gè)模塊:

  • collectionView
    • 四個(gè)section(表情組)
    • 每個(gè)section有多個(gè)cell
    • 自定義cell(20個(gè)表情的button, 還有一個(gè)deleteButton)
  • pageControl
    • 用KVC的方式設(shè)置pageControl的顯示樣式
    • setValueForkey(_currentPageImage)
    • setValueForkey(_pageImage)
  • toolBar
    • 四個(gè)button水平分布
    • 使用UIStackView(專門做平均分布用的, ios9.0以后出來的)

數(shù)據(jù)源使用了一個(gè)emotions.bundle, 創(chuàng)建一個(gè)model, 三維數(shù)組存放數(shù)據(jù)

collectionView, pageControl 和 toolBar三者的聯(lián)動(dòng)

  1. 點(diǎn)擊toolBar做任意一個(gè)button時(shí), pageControl和collectionView的聯(lián)動(dòng)
  2. collectionView上的cell在向左向右滑動(dòng)時(shí), pageControl和toolBar的聯(lián)動(dòng)

第一種聯(lián)動(dòng)實(shí)現(xiàn)起來比較簡單, 就是在點(diǎn)擊toolBar的一個(gè)button時(shí), 利用代理把當(dāng)前被點(diǎn)擊的button tag值傳遞出去, 讓pageControl的當(dāng)前頁為0, collectionViewCell的indexPath.section為tag值, item為0

toolBar四個(gè)button點(diǎn)擊觸發(fā)的方法如下:

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的聯(lián)動(dòng),順便完成toolBar與pageControl的聯(lián)動(dòng)
        emtionCollectionView.scrollToItem(at: indexPath, at: UICollectionViewScrollPosition.left, animated: false)
        
        changePageContol(indexPath: indexPath)
    }
}

第二種聯(lián)動(dòng)實(shí)現(xiàn)則比較復(fù)雜, 用到一個(gè)小技巧:
在scrollViewDidScroll方法里, 計(jì)算可見的兩個(gè)cell的origin.x與當(dāng)前collectionView的.contentOffset.x相減的絕對值進(jìn)行比較

offset與originx的差的絕對值越小, 則顯示的區(qū)域越大

// MARK: - UICollectionViewDelegate
extension WBEmotionKeyBoard: UICollectionViewDelegate {
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        //獲得顯示的cells
        let cells = emtionCollectionView.visibleCells
        //如果屏幕上顯示的cell的cell有兩個(gè)
        if cells.count > 1 {
            let offset = scrollView.contentOffset.x
            //第一個(gè)cell,顯示的區(qū)域
            let cellOne = cells[0]
            //offset與origin.x的絕對值
            let regionOne = abs(cellOne.frame.origin.x - offset)
            //第一個(gè)cell的indexPath
            let indexPathOne = emtionCollectionView.indexPath(for: cellOne)
            
            //第二個(gè)cell
            let cellTwo = cells[1]
            //offset與origin.x的絕對值
            let regionTwo = abs(cellTwo.frame.origin.x - offset)
            //第二個(gè)cell的indexPath
            let indexPathTwo = emtionCollectionView.indexPath(for: cellTwo)
            
            //offset與originx的差的絕對值越小, 則顯示的區(qū)域越大
            if regionOne < regionTwo {
                //使用cellOne的section
                toolBar.index = (indexPathOne?.section)!
                changePageContol(indexPath: indexPathOne!)
            } else {
                //使用cellTwo的section
                toolBar.index = (indexPathTwo?.section)!
                changePageContol(indexPath: indexPathTwo!)
            }
        }
    }
}

定制鍵盤的文件目錄

有興趣的同學(xué)可以看demo的代碼實(shí)現(xiàn)
My github

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,432評論 4 61
  • 首先,讓我懷著感恩的心,給在座的家人們深深鞠一躬。末學(xué)薛子,來自十六期信組,感恩家人們給了我這樣一個(gè)分享的機(jī)會(huì)。 ...
    明德書院閱讀 326評論 0 0
  • 閱讀筆記06 會(huì)用邏輯,你的故事就精彩 《麥肯錫教我的寫作武器》前言、本書架構(gòu) 前言: 一、用有邏輯的故事表達(dá)想法...
    陌上花開l閱讀 531評論 0 1
  • 8月31號(hào)女兒開學(xué),幼兒園升入小學(xué),突然一日三餐都要在家解決,每天都是忙忙碌碌,接送孩子、做飯、收拾,一個(gè)人好累,...
    藍(lán)天里的魚閱讀 581評論 4 4
  • 簡單的是道理,復(fù)雜的是人心。與其說是常識(shí),不如說是牢籠。社會(huì)沒那么繁復(fù),所有發(fā)生的事都對應(yīng)著當(dāng)前的階段,其他的都忽...
    咯咯咯咯咯咯哈閱讀 369評論 0 0

友情鏈接更多精彩內(nèi)容