PHPickerViewController
iOS的相册系统组件UIImagePickerController 目前已经不推荐使用,我们需要逐渐切换到新的组件 PHPickerViewController 上来:
import UIKit
import PhotosUI
class ViewController: UIViewController, UINavigationControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func openClick(_ sender: UIButton) {
var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
configuration.filter = PHPickerFilter.any(of: [.livePhotos, .videos])
configuration.selectionLimit = 1
let picker = PHPickerViewController(configuration: configuration)
picker.delegate = self
present(picker, animated: true, completion: nil)
}
func presentVideoEditor(for url: URL) {
// 调试路径打印
print("Video URL: \(url.path)")
// 确保视频文件路径存在
let fileManager = FileManager.default
if fileManager.fileExists(atPath: url.path) {
print("File exists at path: \(url.path)")
} else {
print("File does not exist at path: \(url.path)")
return
}
// 验证视频是否可编辑
if UIVideoEditorController.canEditVideo(atPath: url.path) {
let editor = UIVideoEditorController()
editor.videoMaximumDuration = 10
editor.videoPath = url.path
editor.delegate = self
present(editor, animated: true, completion: nil)
} else {
print("This video cannot be edited.") // 打印调试信息
}
}
}
extension ViewController: PHPickerViewControllerDelegate {
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true, completion: nil)
guard let provider = results.first?.itemProvider else {
return
}
if provider.hasItemConformingToTypeIdentifier(UTType.movie.identifier) {
provider.loadFileRepresentation(forTypeIdentifier: UTType.movie.identifier) { (url, error) in
if let error = error {
print("Error loading video file: \(error.localizedDescription)")
return
}
guard let tempURL = url else {
print("Error: URL is nil")
return
}
// 拷贝临时文件到合适的位置,以防止被删除
let destinationURL = FileManager.default.temporaryDirectory.appendingPathComponent(tempURL.lastPathComponent)
do {
if FileManager.default.fileExists(atPath: destinationURL.path) {
try FileManager.default.removeItem(at: destinationURL)
}
try FileManager.default.copyItem(at: tempURL, to: destinationURL)
print("Video copied to \(destinationURL)")
// 使用系统的视频编辑器
DispatchQueue.main.async {
self.presentVideoEditor(for: destinationURL)
}
} catch {
print("Error copying video file: \(error.localizedDescription)")
}
}
} else {
print("load file fail!")
}
}
}
extension ViewController: UIVideoEditorControllerDelegate {
func videoEditorController(_ editor: UIVideoEditorController, didSaveEditedVideoToPath editedVideoPath: String) {
editor.dismiss(animated: true, completion: nil)
print("Edited video saved at: \(editedVideoPath)")
}
func videoEditorController(_ editor: UIVideoEditorController, didFailWithError error: Error) {
editor.dismiss(animated: true, completion: nil)
print("Video editing failed with error: \(error.localizedDescription)")
}
func videoEditorControllerDidCancel(_ editor: UIVideoEditorController) {
editor.dismiss(animated: true, completion: nil)
print("Video editing canceled.")
}
}
PHContentEditingController
https://developer.apple.com/documentation/photokit/phcontenteditingcontroller?language=objc_2
https://blog.51cto.com/u_13360/7840126
PHContentEditingController 是 iOS 中用于扩展相册(Photos)应用的接口,允许开发者提供自定义的内容编辑扩展。通过实现这个协议,可以将自己的编辑工具集成到 iOS 相册中,用于编辑照片或视频。
核心概念
扩展点 (Extension Point): PHContentEditingController 被设计为用于 iOS 相册应用的扩展点,允许第三方应用提供自定义的照片或视频编辑功能。
输入 (Input): 相册中的照片或视频作为输入内容传递给 PHContentEditingController。
输出 (Output): 编辑后的内容将以新的形式保存,供用户使用。
实现步骤
创建内容编辑扩展 (Content Editing Extension):
在 Xcode 中创建一个新的目标(Target),选择 "Photo Editing Extension"。这会生成一个包含 PHContentEditingController 协议的模板文件。
实现 PHContentEditingController 方法:
你需要实现以下几个核心方法:
canHandle(_:):判断扩展是否能处理给定的输入内容类型。
startContentEditing(with:placeholderImage:):在用户选择内容后,准备编辑界面。
finishContentEditing(completionHandler:):用户完成编辑后,处理并返回编辑结果。
cancelContentEditing():用户取消编辑时,撤销所有操作。
shouldShowCancelConfirmation():返回一个布尔值,决定是否显示取消编辑的确认提示。
示例代码:
下面是一个基本的实现示例:
import Photos
import UIKit
class PhotoEditingViewController: UIViewController, PHContentEditingController {
var input: PHContentEditingInput?
var isEditingVideo = false
func canHandle(_ adjustmentData: PHAdjustmentData?) -> Bool {
// 检查是否可以处理这个调整数据
return true
}
func startContentEditing(with contentEditingInput: PHContentEditingInput, placeholderImage: UIImage) {
// 保存输入内容
self.input = contentEditingInput
// 检查输入内容是否是视频
if let videoURL = contentEditingInput.audiovisualAsset?.url {
isEditingVideo = true
// 在这里加载并显示视频
} else {
isEditingVideo = false
// 在这里加载并显示图片
}
}
func finishContentEditing(completionHandler: @escaping ((PHContentEditingOutput?) -> Void)) {
guard let input = input else {
completionHandler(nil)
return
}
// 创建编辑输出对象
let output = PHContentEditingOutput(contentEditingInput: input)
if isEditingVideo {
// 视频处理逻辑
// 保存修改后的视频到 output.renderedContentURL
} else {
// 图片处理逻辑
// 保存修改后的图片到 output.renderedContentURL
}
// 生成调整数据
let adjustmentData = PHAdjustmentData(formatIdentifier: "com.yourcompany.appname", formatVersion: "1.0", data: Data())
output.adjustmentData = adjustmentData
// 调用回调并传递输出结果
completionHandler(output)
}
func cancelContentEditing() {
// 处理用户取消编辑的情况
}
func shouldShowCancelConfirmation() -> Bool {
// 返回是否应该显示取消确认提示
return true
}
}
关键点说明:
PHContentEditingInput 和 PHContentEditingOutput: 这两个类用于在编辑过程中处理输入和输出内容。
PHAdjustmentData: 用于保存编辑操作的元数据,以便将来恢复或重新应用这些操作。
注意事项
这个扩展是直接与系统相册集成的,用户可以在相册应用中使用你的自定义编辑器。
确保正确处理用户的操作,无论是保存编辑结果还是取消编辑,都要提供流畅的用户体验。
如果你需要进一步了解或实现具体功能,随时告诉我!
网友评论