You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:26:05