目标与计划
目标
假设一个场景,我们的app需要图片,这个图片的来源是相册或者通过拍照获取的,并且要将图片保留在app中,并且希望app打开时能遍历到某个目录下的所有图片,并且加载,以供我们的app使用。
计划
构建一个View,在这个View中选择相册中的图片,或者通过相机拍照
选中的图片保存到app中,并且在app打开时加载指定目录的图片
构造一个外层容器用来装载这个View
计划完成,开始动手写代码
实现
构建从相册/相机选择图片的View
SwiftUI没有这个样的控件,需要使用UIKit中的UIImage这个控件,那么这里需要一个技术,SwifiUI桥接UIKit控件。那么现在不讲原理,只讲如何实现。
定义一个Struct继承UIViewControllerRepresentable,在继承时,需要实现2个func,makeUIViewController和updateUIViewController一个是在构造时调用一个是在刷新时被调用.在这个Struct中可以打开相册/相机 (使用摄像头需要在info.plist中添加一个Privacy - Camera Usage Description 的授权描述)
struct ImagePicker: UIViewControllerRepresentable {
@Binding var sourceType:UIImagePickerController.SourceType
func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
let picker=UIImagePickerController()
picker.allowsEditing=false
picker.sourceType=sourceType
print("picker source \(sourceType.rawValue)")
return picker
}
func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {
}
}
在这段代码中定义了一个ImagePicker的View,继承了UIViewControllerRepresentable,添加了一个sourceType的属性,用来控制图片来源(相册还是相机)。在makeUIViewController函数中,创建UIImagePickerController的实例,并且设置图片是不可编辑的,设置了来源。
我们完成了一个打开相册或者相机的View。但打开之后,选择图片是没有任何反应的,这个就需要我们做另一个事情,添加一个代理处理选照片的这个事件。(具体原理需可查阅UIKit相关文档。这里只实现功能),定义一个类继承NSObject,UINavigationControllerDelegate,UIImagePickerControllerDelegate。
struct ImagePicker: UIViewControllerRepresentable {
@Binding var sourceType:UIImagePickerController.SourceType
let handlerImage:(_ image:UIImage)->Void
func makeCoordinator() -> Coordinator {
return Coordinator(self)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<