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

iOS Swift实现备忘录功能:将相册视频插入TextView

提问内容

我尝试过相关方法但均未成功,希望实现类似备忘录的功能:从相册选择视频并将其显示在TextView中。

我的代码如下:

extension DetailViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        
        videoURL = info[UIImagePickerController.InfoKey(rawValue: "UIImagePickerControllerReferenceURL") ] as? NSURL
        
        print(videoURL!)
        
        do {
            
            let asset = AVURLAsset(url: videoURL! as URL , options: nil)
            
            let imgGenerator = AVAssetImageGenerator(asset: asset)
            
            imgGenerator.appliesPreferredTrackTransform = true
            
            let cgImage = try imgGenerator.copyCGImage(at: CMTimeMake(value: 0, timescale: 1), actualTime: nil)
            
            let thumbnail = UIImage(cgImage: cgImage)
            
            selectedImage = thumbnail
            
        } catch let error {
            
            print("*** Error generating thumbnail: \(error.localizedDescription)")
       
        }
        
        if var selectedImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
            
            let attachment = NSTextAttachment()
            
            if selectedImage.imageOrientation == .up || selectedImage.imageOrientation == .down {
                
                let img = selectedImage.resizeImage(image: selectedImage, targetSize: CGSize(width: self.view.frame.width - 50, height: self.view.frame.height))
                
                attachment.image = img.imageWithSpacing(insets: UIEdgeInsets(top: 15, left: 0, bottom: 15, right: 0))
                
            } else {
                
                let img = selectedImage.resizeImage(image: selectedImage, targetSize: CGSize(width: self.view.frame.width - 50, height: self.view.frame.height))
                
                attachment.image = img.imageWithSpacing(insets: UIEdgeInsets(top: 15, left: 0, bottom: 15, right: 0))
                
            }
            
            let attString = NSAttributedString(attachment: attachment)
            
            textView.textStorage.insert(attString, at: textView.selectedRange.location)
            
            picker.dismiss(animated: true, completion: nil)
            
        }
        
        let player = AVPlayer(url: videoURL! as URL)
        
        let playerController = AVPlayerViewController()
        
        playerController.player = player
        
        self.present(playerController, animated: true) {
            
            player.play()
            
        }
        
        let newPosition = textView.endOfDocument
        
        textView.selectedTextRange = textView.textRange(from: newPosition, to: newPosition)
        
        dismiss(animated: true, completion: nil)
        
    }
    
}

我想了解如何将选中的视频正确插入TextView中,是否可以将videoURL转换为其他格式放入NSTextAttachment,或是该需求无法实现?


解决方案

TextView本身无法直接嵌入可播放的视频,但可以通过以下方式实现类似备忘录的效果:

1. 插入视频缩略图并绑定点击播放逻辑

NSTextAttachment仅支持承载图片,不能直接存储视频URL或文件。你可以用生成的视频缩略图作为附件插入TextView,再给缩略图添加点击手势触发播放:

核心修改步骤:

  • 废弃原代码中依赖info[.originalImage]的逻辑(视频选择时不会返回该值),直接用你生成的thumbnail创建NSTextAttachment
  • 自定义NSTextAttachment子类,用来绑定对应的视频URL
  • 给TextView添加点击手势,判断点击位置是否为视频缩略图附件,触发播放

修改后的核心代码片段:

// 替换原代码中if var selectedImage = info[...]的部分
if let thumbnail = selectedImage {
    // 自定义附件类存储视频URL
    class VideoAttachment: NSTextAttachment {
        var videoURL: URL?
    }
    
    let videoAttachment = VideoAttachment()
    // 调整缩略图为16:9比例,适配TextView显示
    let targetSize = CGSize(width: self.view.frame.width - 50, height: (self.view.frame.width - 50) * 9 / 16)
    let resizedImg = thumbnail.resizeImage(image: thumbnail, targetSize: targetSize)
    videoAttachment.image = resizedImg.imageWithSpacing(insets: UIEdgeInsets(top: 15, left: 0, bottom: 15, right: 0))
    videoAttachment.videoURL = videoURL as URL?
    
    let attString = NSAttributedString(attachment: videoAttachment)
    textView.textStorage.insert(attString, at: textView.selectedRange.location)
    
    picker.dismiss(animated: true, completion: nil)
}

// 在viewDidLoad中添加TextView点击手势
override func viewDidLoad() {
    super.viewDidLoad()
    let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTextViewTap(_:)))
    textView.addGestureRecognizer(tapGesture)
}

// 点击处理方法
@objc func handleTextViewTap(_ gesture: UITapGestureRecognizer) {
    let location = gesture.location(in: textView)
    guard let position = textView.closestPosition(to: location),
          let attachment = textView.textStyling(at: position, in: .forward)?.attachment as? VideoAttachment,
          let url = attachment.videoURL else {
        return
    }
    // 播放视频
    let player = AVPlayer(url: url)
    let playerController = AVPlayerViewController()
    playerController.player = player
    present(playerController, animated: true) {
        player.play()
    }
}

2. 额外优化点

  • 原代码中UIImagePickerControllerReferenceURL已废弃,建议改用UIImagePickerController.InfoKey.mediaURL获取视频本地URL
  • 可以给缩略图叠加播放图标,让用户明确这是可点击的视频元素
  • 确保已在Info.plist中添加相册访问权限申请(NSPhotoLibraryUsageDescription)

内容的提问来源于stack exchange,提问作者Note The

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 18:50:33