美文网首页iOS点点滴滴
swift - 自定义表情键盘 + 如何和后台交互

swift - 自定义表情键盘 + 如何和后台交互

作者: 灵儿菇凉 | 来源:发表于2017-11-27 18:21 被阅读0次

    自定义表情视图(collectionView+自定义UICollectionViewFlowLayout)

    image.png

    HQEmjioView是定义的表情视图类,HQEmjioCell是collectionview的cell,HQEmjioTool是一些工具类的封装。

    首先我们自定义一个表情键盘的思路就是
    1、先把表情键盘页面写好,包括一些代理事件,表情布局等。
    2、视图写好以后会去思考事件。包括表情点击如何展示在textView上,表情的添加和删除,点击发送如何把数据传给后台,以及如何将后台发来的数据还原。这里我们用到了一个很重要的属性NSAttributedString,通过富文本去实现这一系列的操作。

    具体代码思路
    1、懒加载表情视图

     private lazy var emjioView:HQEmjioView? = HQEmjioView.emjioView()
    

    2、监听键盘

    func addKeyBoardNotification() {
            let notif = NotificationCenter.default
            notif.addObserver(self,
                              selector: #selector(keyboardWillChangeFrame),
                              name: .UIKeyboardWillChangeFrame,
                              object: nil)
        }
    

    3、键盘响应时做出相应的操作

        /// 键盘响应通知
        @objc func keyboardWillChangeFrame(_ note: Notification) {
         
            guard let kbInfo = note.userInfo,
            let duration = kbInfo[UIKeyboardAnimationDurationUserInfoKey] as? TimeInterval,
            let kbFrameInfo = kbInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue else {
                return
            }
            let kbFrame = kbFrameInfo.cgRectValue
            let kbInset = UIScreen.main.bounds.size.height - (kbFrame.minY) // 键盘偏移量
            let animationCurve = kbInfo[UIKeyboardAnimationCurveUserInfoKey] as! UInt
    
            if kbInset > 0.0 {
                UIView.animate(withDuration: duration, delay: 0.0,
                               options: UIViewAnimationOptions(rawValue: animationCurve),
                               animations: { () -> Void in
                                
                                self.viewBottomConstrains.constant = -(kbInset)
                                self.view.layoutIfNeeded()
                                
                }, completion: {(finished) -> () in
                })
            } else {
                self.viewBottomConstrains.constant = self.bottomLayoutGuide.length
            }
            
        }
    

    4、表情按钮点击时切换键盘

    @IBAction func emjioBtnClick(_ sender: UIButton) {
            textView.resignFirstResponder()
            sender.isSelected = !sender.isSelected
            if sender.isSelected {
                textView.inputView = self.emjioView
            }else {
                textView.inputView = nil
            }
            textView.becomeFirstResponder()
        }
    

    5、点击按钮让表情显示在textview上

        func emjioSelect(attachment: NSAttributedString) {
            /// 在插入表情时先判断是否有选择的字符,如果有选择则先删除选择的字符再进行插入操作
            if textView.selectedRange.length > 0 {
                textView.textStorage.deleteCharacters(in: textView.selectedRange)
                textView.selectedRange = NSMakeRange(textView.selectedRange.location, 0)
            }
            textView.textStorage.insert(attachment, at: textView.selectedRange.location)
            textView.selectedRange = NSMakeRange(textView.selectedRange.location + 1, textView.selectedRange.length)
            textViewDidChange(textView)
        }
    // 将表情图片转化为可以显示的富文本 - HQEmjioTool.swift
    func getAttachment(imageName:String,dic:(String,String)) -> NSAttributedString {
            let attachment = HQTextAttachment()
            attachment.text = dic.0
            attachment.image = UIImage(named: imageName)
            attachment.bounds = CGRect(x: 0, y: -4, width: 16, height: 16)
            let attributedStr = NSAttributedString(attachment: attachment)
            let muAtt = NSMutableAttributedString(attributedString: attributedStr)
            muAtt.addAttribute(.font, value: UIFont.systemFont(ofSize: 14), range: NSRange(location: 0, length: muAtt.length))
            return muAtt
        }
    

    6、删除表情、和TextView自适应大小

    func emjioDelete() {
            if textView.selectedRange.length > 0 {
                let range = textView.selectedRange
                textView.textStorage.deleteCharacters(in: range)
                textView.selectedRange = NSMakeRange(range.location, 0)
            } else if textView.selectedRange.location > 0 {
                let range = NSMakeRange(textView.selectedRange.location - 1, 1)
                textView.textStorage.deleteCharacters(in: range)
                textView.selectedRange = NSMakeRange(range.location, 0)
            }
            textViewDidChange(textView)
        }
        // textView自适应大小
        func textViewDidChange(_ textView: UITextView) {
            var bounds = textView.bounds
            let maxSize = CGSize(width: bounds.size.width, height: CGFloat.greatestFiniteMagnitude)
            let newSize = textView.sizeThatFits(maxSize)
            bounds.size.height = newSize.height
            if bounds.size.height < MAX_HEIGHT {
                viewHeightConstrains.constant = bounds.size.height > 36 ? bounds.size.height : 36
                textView.isScrollEnabled = false
            }else {
                viewHeightConstrains.constant = MAX_HEIGHT
                textView.isScrollEnabled = true
            }
        }
    

    7、如何将系统键盘改为发送,并监听发送事件

     textView.returnKeyType = .send
     func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
            if text == "\n" {
                sendBtnClick()
                return false
            }
            return true
      }
    

    8、如何将TextView中的属性文字以字符串的形式发送给后台(后台是不支持直接属性文字的)- HQEmjioTool.swift

    // 将表情文字转化成后台能接收的文字
        func plainText() -> (String) {
            let plainStr = NSMutableString(string: string)
            var base = 0
            enumerateAttribute(NSAttributedStringKey.attachment,
                               in: NSMakeRange(0, length),
                               options: NSAttributedString.EnumerationOptions(rawValue: 0)) { (value, range, stop) -> Void in
                                if let attachment = value as? HQTextAttachment {
                                    plainStr.replaceCharacters(in: NSMakeRange(range.location + base, range.length), with: attachment.text)
                                    base += attachment.text.characters.count - 1
                                }
            }
            return (plainStr as String)
        }
    

    9、如何将后台发送回来的数据转化成属性文字再显示出来

    // 将后台发过来的文字转化成能显示给用户的文字
         func attributedText(withChatMsg content: String) -> NSMutableAttributedString {
            
            let attrContent = NSMutableAttributedString(string: content)
            do {
                let regex = try NSRegularExpression(pattern: regulaPattern, options: .caseInsensitive)
                let allMatches = regex.matches(in: content,
                                               options: NSRegularExpression.MatchingOptions(rawValue: 0),
                                               range: NSMakeRange(0, attrContent.length))
                let resultAttrString = NSMutableAttributedString()
                var range = NSMakeRange(0, 0)
                for match in allMatches {
                    var emotionPath = ""
                    
                    if match.range.location != range.location {
                        range.length = match.range.location - range.location
                        resultAttrString.append(attrContent.attributedSubstring(from: range))
                    }
                    range.location = match.range.location + match.range.length
                    if match.range.length > 0 {
                        let emot = attrContent.attributedSubstring(from: match.range)
                        for emotDic in emotions() {
                            if emotDic.0 == emot.string {
                                emotionPath = emotPath + emotDic.1
                                resultAttrString.append(getAttachment(imageName: emotionPath, dic: emotDic))
                                break
                            }
                        }
                        if emotionPath == "" {
                            resultAttrString.append(emot) // 找不到对应图像名称就直接加上去
                        }
                    }
                }
                if range.location != attrContent.length {
                    range.length = attrContent.length - range.location
                    resultAttrString.append(attrContent.attributedSubstring(from: range))
                }
                return resultAttrString
            } catch let error {
                print(error)
            }
            return attrContent
        }
    }
    变成属性文字的过程。。。
    

    具体如何自定义collectionview的表情键盘可以看我项目里面的代码。GitHub

    相关文章

      网友评论

        本文标题:swift - 自定义表情键盘 + 如何和后台交互

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