专业java、php、iOS、C++、网页设计、平面设计、网络营销、游戏开发、前端与移动开发培训机构

插入emoji和图片到textView

  • 当点击表情的时候需要将表情插入到 textVew 中.需要知道点击的是那个表情,在 CZEmoticonPageCell 创建按钮的时候给按钮添加点击事件

    /**
    添加20个表情按钮到cell里面
    */
    private func addEmoticonButtons() {
      for _ in 0..<HMEmoticonNumberOfPage {
          // 创建按钮
          let button = HMEmoticonButton()
          button.backgroundColor = UIColor.random
    
          button.addTarget(self, action: #selector(didClickEmoticonButton(button:)), for: UIControlEvents.touchUpInside)
    
          // 按钮添加到contentView
          contentView.addSubview(button)
    
          // 将按钮添加到数组,方便后面遍历按钮
          emoticonButtons.append(button)
      }
    }
    /**
    按钮点击事件
    parameter emoticonButton: 被点击的按钮
    */
    @objc private func didClickEmoticonButton(button: HMEmoticonButton) {
      print("点击了: \(button)")
    }
    
  • 目前是在 HMEmoticonPageCell 里面响应点击事件,需要将点击事件传递给 HMEmoticonKeyboard, 使用代理来实现,在 HMEmoticonPageCell 定义 HMEmoticonPageCellDelegate
    protocol HMEmoticonPageCellDelegate: NSObjectProtocol {
      /// 表情按钮点击的代理事件
      func emoticonPageCell(didSelectedEmoticon emoticon: HMEmoticonModel)
    }
    
  • HMEmoticonPageCell 定义 delegate 属性
    /// 代理
    weak var delegate: HMEmoticonPageCellDelegate?
    
  • HMEmoticonPageCell 的按钮点击方法 didClickEmoticonButton 中调用代理的 emoticonKeyboardPageCell:didSelectedEmoticon:
    /**
    按钮点击事件
    parameter emoticonButton: 被点击的按钮
    */
    @objc private func didClickEmoticonButton(button: HMEmoticonButton) {
    //        print("点击了: \(button)")
      delegate?.emoticonPageCell(didSelectedEmoticon: button.emoticon!)
    }
    
  • HMEmoticonKeyboardcellForItemAtIndexPath 设置 selfcell 的代理

    // 返回cell
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
      let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! HMEmoticonPageCell
    
      // 设置为cell的代理
      cell.delegate = self
    
      cell.indexPath = indexPath
      cell.pageEmoticons = HMEmoticonManager.shared.packages[indexPath.section].pageEmoticons[indexPath.item]
    
      return cell
    }
    
  • HMEmoticonKeyboard 实现 HMEmoticonPageCellDelegate
    // MARK: - 扩展 HMEmoticonKeyboard 实现 HMEmoticonPageCellDelegate 协议
    extension HMEmoticonKeyboard: HMEmoticonPageCellDelegate {
      func emoticonPageCell(didSelectedEmoticon emoticon: HMEmoticonModel) {
          print("我在keyboard里面知道了cell点击了表情: \(emoticon)")
      }
    }
    
  • 至此,在 HMEmoticonKeyboard 就能响应表情按钮的点击事件了
  • 插入 emoji图片textView 其实就是修改 textViewtext,所以 HMEmoticonKeyboard 需要拥有 textView
    • HMEmoticonKeyboard 定义 textView 属性
      /// textView
      weak var textView: UITextView?
      
    • ViewController 创建 HMEmoticonKeyboard 的时候设置 textView
  • 插入 emoji 表情
  • HMEmoticonKeyboard 定义 insertEmoticon 方法来 插入表情到 textView

    extension HMEmoticonKeyboard: HMEmoticonPageCellDelegate {
      func emoticonPageCell(didSelectedEmoticon emoticon: HMEmoticonModel) {
          insertEmoticon(emoticon: emoticon)
      }
    
      /**
       插入表情到textView
       parameter emoticon: 表情模型
       */
      func insertEmoticon(emoticon: HMEmoticonModel) {
          // 判断textView是否有值
          guard let textView = self.textView else {
              print("textView 为空")
              return
          }
    
          // 插入emoji
          if let emoji = emoticon.emoji {
              textView.insertText(emoji)
              print("插入emoji: \(textView.text)")
          }
      }
    }
    
  • 运行,可以添加 emoji 表情了
  • 插入 图片textView,要将图片添加到 textView 需要使用附件 NSTextAttachment, 在 HMEmoticonKeyboardinsertEmoticon 将图片添加到 textView

    /**
    插入表情到textView
    parameter emoticon: 表情模型
    */
    func insertEmoticon(emoticon: HMEmoticonModel) {
      // 判断textView是否有值
      guard let textView = self.textView else {
          print("textView 为空")
          return
      }
    
      // 插入emoji
      if let emoji = emoticon.emoji {
          textView.insertText(emoji)
          return
      }
    
      // 插入表情图片,需要使用到属性文本
      if let pngPath = emoticon.fullPngPath {
          // 附件,图片可以作为附件,附件可以添加到属性文本
          let attachment = NSTextAttachment()
          attachment.image = UIImage(contentsOfFile: pngPath)
    
          let attrString = NSAttributedString(attachment: attachment)
    
          textView.attributedText = attrString
      }
    }
    
  • 运行,可以添加图片到 textView 但是发现文字没有了.不能直接将现有文本给覆盖了.需要获取到 textView 现有 text,将附件替换到光标的位置

    // 插入表情图片,需要使用到属性文本
    if let pngPath = emoticon.fullPngPath {
      // 附件,图片可以作为附件,附件可以添加到属性文本
      let attachment = NSTextAttachment()
      attachment.image = UIImage(contentsOfFile: pngPath)
    
      // 创建带附件的属性文本
      let attrString = NSAttributedString(attachment: attachment)
    
      // 获取textView现有文本
      let attrStringM = NSMutableAttributedString(attributedString: textView.attributedText)
    
      // 替换属性文本到对应的位置
      attrStringM.replaceCharacters(in: textView.selectedRange, with: attrString)
    
      // 将属性文本设置给textView
      textView.attributedText = attrStringM
    }
    
  • 插入图片后光标跑到最后面位置,先记录下光标位置,在赋值属性文本后重新设置光标位置

    // 插入表情图片,需要使用到属性文本
    if let pngPath = emoticon.fullPngPath {
      // 附件,图片可以作为附件,附件可以添加到属性文本
      let attachment = NSTextAttachment()
      attachment.image = UIImage(contentsOfFile: pngPath)
    
      // 创建带附件的属性文本
      let attrString = NSAttributedString(attachment: attachment)
    
      // 获取textView现有文本
      let attrStringM = NSMutableAttributedString(attributedString: textView.attributedText)
    
      // 光标位置
      let oldSelectedRange = textView.selectedRange
    
      // 替换属性文本到对应的位置
      attrStringM.replaceCharacters(in: oldSelectedRange, with: attrString)
    
      // 将属性文本设置给textView
      textView.attributedText = attrStringM
    
      // 重新设置光标位置
      textView.selectedRange = NSRange(location: oldSelectedRange.location + 1, length: 0)
    }
    
  • 直接添加到 textView 的图片比较大,需要设置图片的大小

    // 插入表情图片,需要使用到属性文本
    if let pngPath = emoticon.fullPngPath {
      // 附件,图片可以作为附件,附件可以添加到属性文本
      let attachment = NSTextAttachment()
      attachment.image = UIImage(contentsOfFile: pngPath)
    
      // 获取文本的高度
      let height = textView.font?.lineHeight ?? 10
      // 设置附件的大小
      attachment.bounds = CGRect(x: 0, y: -4, width: height, height: height)
    
      // 创建带附件的属性文本
      let attrString = NSAttributedString(attachment: attachment)
    
      // 获取textView现有文本
      let attrStringM = NSMutableAttributedString(attributedString: textView.attributedText)
    
      // 光标位置
      let oldSelectedRange = textView.selectedRange
    
      // 替换属性文本到对应的位置
      attrStringM.replaceCharacters(in: oldSelectedRange, with: attrString)
    
      // 将属性文本设置给textView
      textView.attributedText = attrStringM
    
      // 重新设置光标位置
      textView.selectedRange = NSRange(location: oldSelectedRange.location + 1, length: 0)
    }
    
  • 在表情图片后面在插入一张表情会发现表情图片变小了.原因是附件没有 font 属性,在通过附件创建属性文本的时候设置属性文本的 font

    // 插入表情图片,需要使用到属性文本
    if let pngPath = emoticon.fullPngPath {
      // 附件,图片可以作为附件,附件可以添加到属性文本
      let attachment = NSTextAttachment()
      attachment.image = UIImage(contentsOfFile: pngPath)
    
      // 获取文本的高度
      let height = textView.font?.lineHeight ?? 10
      // 设置附件的大小
      attachment.bounds = CGRect(x: 0, y: -4, width: height, height: height)
    
      // 创建带附件的属性文本,并且添加font属性
      let attrString = NSMutableAttributedString(attributedString: NSAttributedString(attachment: attachment))
      attrString.addAttribute(NSFontAttributeName, value: textView.font!, range: NSRange(location: 0, length: 1))
    
      // 获取textView现有文本
      let attrStringM = NSMutableAttributedString(attributedString: textView.attributedText)
    
      // 光标位置
      let oldSelectedRange = textView.selectedRange
    
      // 替换属性文本到对应的位置
      attrStringM.replaceCharacters(in: oldSelectedRange, with: attrString)
    
      // 将属性文本设置给textView
      textView.attributedText = attrStringM
    
      // 重新设置光标位置
      textView.selectedRange = NSRange(location: oldSelectedRange.location + 1, length: 0)
    }
    
  • 至此,添加图片到 textView 上面就好了

实现删除按钮删除 textView 的文字和表情

  • HMEmoticonPageCellDelegate 添加点击了删除按钮的协议方法 emoticonPageCellDidClickDeleteButton

    protocol HMEmoticonPageCellDelegate: NSObjectProtocol {
      /// 表情按钮点击的代理事件
      func emoticonPageCell(didSelectedEmoticon emoticon: HMEmoticonModel)
    
      /// 删除按钮点击的代理事件
      func emoticonPageCellDidClickDeleteButton()
    }
    
  • HMEmoticonPageCelldeleteButton 懒加载里面添加点击事件

    /// 删除按钮
    private lazy var deleteButton: UIButton = {
      let button = UIButton()
    
      button.setImage(UIImage(named: "compose_emotion_delete"), for: UIControlState.normal)
      button.setImage(UIImage(named: "compose_emotion_delete_highlighted"), for: UIControlState.highlighted)
    
      button.addTarget(self, action: #selector(didClickdeleteButton), for: .touchUpInside)
    
      return button
    }()
    
    /// 删除按钮点击事件
    func didClickdeleteButton() -> Void {
      delegate?.emoticonPageCellDidClickDeleteButton()
    }
    
  • HMEmoticonKeyboard 实现 HMEmoticonPageCellDelegate 协议的 deleteButtonClick 方法中删除 textView 的文字

    extension HMEmoticonKeyboard: HMEmoticonPageCellDelegate {
      func emoticonPageCellDidClickDeleteButton() {
          textView?.deleteBackward()
      }
    
      func emoticonPageCell(didSelectedEmoticon emoticon: HMEmoticonModel) {
          insertEmoticon(emoticon: emoticon)
      }
      ...
    }
    

results matching ""

    No results matching ""