iOS Swift:如何为TextView中的NSTextAttachment添加点击识别?
识别NSTextAttachment的点击操作方案
因为NSTextAttachment并非UIView子类,无法直接添加手势识别器,我们需要通过监听UITextView的点击事件,判断点击位置是否落在附件区域内来实现需求。
具体实现步骤
- 为
UITextView添加点击手势 - 在手势回调中计算点击位置对应的文本索引
- 检查该索引处的属性是否包含
NSTextAttachment - 确认是附件后执行对应逻辑
代码实现
1. 修改表格单元格配置代码
在cellForRowAt中为文本视图添加手势,并绑定行号用于后续定位数据:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "ChatTableViewCell", for: indexPath) as! ChatTableViewCell let attachment = messageData[indexPath.row].attachment let attributedText2 = NSMutableAttributedString(string: messageData[indexPath.row].message + "\n\n") let attachmentString = NSAttributedString(attachment: attachment) attributedText2.append(attachmentString) // 可选:给附件对应的文本范围添加自定义标记,提升判断准确性 let attachmentRange = NSRange(location: attributedText2.length - attachmentString.length, length: attachmentString.length) attributedText2.addAttribute(NSAttributedString.Key(rawValue: "isAttachment"), value: true, range: attachmentRange) cell.chatTextView.attributedText = attributedText2 cell.chatTextView.isEditable = false cell.chatTextView.isSelectable = false // 避免重复添加手势 cell.chatTextView.gestureRecognizers?.removeAll(where: { $0 is UITapGestureRecognizer }) let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleAttachmentTap(_:))) cell.chatTextView.addGestureRecognizer(tapGesture) cell.chatTextView.tag = indexPath.row return cell }
2. 实现点击回调逻辑
@objc func handleAttachmentTap(_ gesture: UITapGestureRecognizer) { guard let textView = gesture.view as? UITextView else { return } let tapLocation = gesture.location(in: textView) // 获取点击位置对应的文本位置 guard let textPosition = textView.closestPosition(to: tapLocation), let range = textView.textRange(from: textPosition, to: textPosition) else { return } let characterIndex = textView.offset(from: textView.beginningOfDocument, to: textPosition) guard let attributedText = textView.attributedText else { return } // 获取该位置的文本属性 let attributes = attributedText.attributes(at: characterIndex, effectiveRange: nil) // 验证是否为目标附件 if attributes[NSAttributedString.Key(rawValue: "isAttachment")] as? Bool == true, let attachment = attributes[.attachment] as? NSTextAttachment { let row = textView.tag let targetData = messageData[row] // 这里执行附件点击后的逻辑,比如预览图片、跳转等 print("点击了第\(row)行的附件:\(attachment)") } }
注意事项
- 确保
UITextView的isEditable设为false,避免系统默认交互干扰手势触发 - 若需要保留文本选择功能,可将
isSelectable设为true,并调整手势的cancelsTouchesInView属性为false
内容的提问来源于stack exchange,提问作者husharoonie
相关产品推荐
相关产品推荐

