专业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!) }
在
HMEmoticonKeyboard
的cellForItemAtIndexPath
设置self
为cell
的代理// 返回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
其实就是修改textView
的text
,所以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
, 在HMEmoticonKeyboard
的insertEmoticon
将图片添加到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() }
在
HMEmoticonPageCell
的deleteButton
懒加载里面添加点击事件/// 删除按钮 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) } ... }