UITextView拖拽交互如何一次仅接受一种对象类型?
解决UITextView拖放时同时接受图片和URL文本的问题
这个问题其实很常见——从网页拖拽图片时,系统的拖放会话里同时包含了图片资源和图片的URL文本两种可加载的类型,所以你的performDrop方法里两个loadObjects调用都会触发,导致同时插入图片和URL。
要实现一次仅接受一种类型,我们可以通过优先判断并只处理目标类型的方式来解决,下面给你两种可行的方案:
方案1:按优先级处理类型
先检查会话中是否存在图片类型,如果有就只处理图片;否则再处理文本。这样能确保同一时间只处理一种类型:
import MobileCoreServices // 别忘了导入这个框架 func dropInteraction(_ interaction: UIDropInteraction, performDrop session: UIDropSession) { // 优先处理图片类型 if session.hasItemsConforming(toTypeIdentifiers: [kUTTypeImage as String]) { session.loadObjects(ofClass: UIImage.self) { [weak self] imageItems in guard let self = self, let image = imageItems.first as? UIImage else { return } // 将图片插入到UITextView(用NSTextAttachment实现图文混排) let attachment = NSTextAttachment() attachment.image = image // 可以调整图片大小适配文本行高 let lineHeight = self.textView.font?.lineHeight ?? 16 attachment.bounds = CGRect(x: 0, y: -(lineHeight - image.size.height)/2, width: image.size.width, height: image.size.height) let attributedString = NSAttributedString(attachment: attachment) DispatchQueue.main.async { self.textView.textStorage.insert(attributedString, at: self.textView.selectedRange.location) } } } // 没有图片时再处理文本 else if session.hasItemsConforming(toTypeIdentifiers: [kUTTypeText as String]) { session.loadObjects(ofClass: NSString.self) { [weak self] stringItems in guard let self = self, let text = stringItems.first as? String else { return } DispatchQueue.main.async { self.textView.insert(text, at: self.textView.selectedRange.location) } } } }
方案2:逐个检查拖放Item的类型
如果你需要更精细的控制,可以遍历会话中的每个Item,检查它的类型标识符,处理完目标类型后直接返回,避免处理其他类型:
import MobileCoreServices func dropInteraction(_ interaction: UIDropInteraction, performDrop session: UIDropSession) { for item in session.items { let itemProvider = item.itemProvider // 优先处理图片 if itemProvider.hasItemConformingToTypeIdentifier(kUTTypeImage as String) { itemProvider.loadObject(ofClass: UIImage.self) { [weak self] object, error in guard let self = self, let image = object as? UIImage, error == nil else { return } DispatchQueue.main.async { let attachment = NSTextAttachment() attachment.image = image let lineHeight = self.textView.font?.lineHeight ?? 16 attachment.bounds = CGRect(x: 0, y: -(lineHeight - image.size.height)/2, width: image.size.width, height: image.size.height) let attributedString = NSAttributedString(attachment: attachment) self.textView.textStorage.insert(attributedString, at: self.textView.selectedRange.location) } } return // 处理完图片就退出,不处理其他类型 } // 处理文本 else if itemProvider.hasItemConformingToTypeIdentifier(kUTTypeText as String) { itemProvider.loadObject(ofClass: NSString.self) { [weak self] object, error in guard let self = self, let text = object as? String, error == nil else { return } DispatchQueue.main.async { self.textView.insert(text, at: self.textView.selectedRange.location) } } return } } }
关键说明
- 网页拖拽的
NSItemProvider通常会同时支持多种类型(比如图片、URL文本),所以原来的代码中两个loadObjects都会成功回调,导致同时插入内容。 - 通过优先判断+提前返回的逻辑,我们确保了同一拖放操作只处理一种类型的内容。
- 插入图片时使用
NSTextAttachment是UITextView中实现图文混排的标准方式,你可以根据需求调整图片的大小和位置。
内容的提问来源于stack exchange,提问作者Ivan Cantarino
相关产品推荐
相关产品推荐

