我提出一个 UIImagePickerController
在我的应用程序中,通过在一个 sheet
修饰符。简而言之,以下三种类型处理了显示和驳回一个 UIImagePickerController
内 UIViewControllerRepresentable
类型,工作正常。
struct DetailsView: View {
enum Sheet: Hashable, Identifiable {
case takePhoto
var id: Int { hashValue }
}
@State private var activeSheet: Sheet?
var body: some View {
Text("Hello, World!")
.sheet(item: $activeSheet) { (sheet) in self.view(for: sheet) }
}
private func view(for sheet: Sheet) -> some View {
switch sheet {
case .takePhoto: return PhotoSelectionView(showImagePicker: .init(get: { sheet == .takePhoto }, set: { (show) in self.activeSheet = show ? .takePhoto : nil }), image: $selectedImage, photoSource: .camera).edgesIgnoringSafeArea(.all)
}
}
}
struct ImagePicker: UIViewControllerRepresentable {
@Binding var isShown: Bool
@Binding var image: Image?
let photoSource: PhotoSource
func makeCoordinator() -> ImagePickerCoordinator {
return ImagePickerCoordinator(isShown: $isShown, selectedImage: $image)
}
func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {
}
func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
let imagePicker = UIImagePickerController()
if photoSource == .camera, UIImagePickerController.isSourceTypeAvailable(.camera) {
imagePicker.sourceType = .camera
imagePicker.cameraCaptureMode = .photo
}
imagePicker.delegate = context.coordinator
return imagePicker
}
}
class ImagePickerCoordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
@Binding private var isShown: Bool
@Binding private var selectedImage: Image?
init(isShown: Binding<Bool>, selectedImage: Binding<Image?>) {
_isShown = isShown
_selectedImage = selectedImage
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
// handle photo selection
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss()
}
}
我遇到的问题是摄像机的视图是以模式化的方式呈现的,并没有覆盖整个屏幕。这将导致 UIImagePickerController
以至于在摄像机为源时,有时会出现布局破碎的情况,就好像摄像机不是为了以这种方式呈现一样。设置 imagePicker.modalPresentationStyle = .fullScreen
不会导致全屏显示。
如何在全屏布局中显示摄像头,使其不出现卡片式的展示方式?
好吧,请带着大把的盐分接受这个答案。我可能会因此而被降权到地狱,我所有的编码孩子和我一起 ... 但苹果也应该为没有在SwiftUI中提供一个简单的方法来全屏显示一个UIImagePickerController而负责。
该 糟透了 诀窍是在rootView中创建你的picker,并让它忽略安全区域,然后将所有必要的参数作为绑定传给需要imagePicker的视图。然后将所有必要的参数作为绑定传递给需要imagePicker的视图。
struct mainView: View {
@State private var imagePicked = UIImage()
@State private var showImagePicker = false
@State private var pickerSource = UIImagePickerController.SourceType.camera
var body: some View {
ZStack {
AvatarView(showImagePicker: self.$showImagePicker, pickerSource: self.$pickerSource , imagePicked: self.$imagePicked)
if self.showImagePicker {
ImagePickerView(isPresented: self.$showImagePicker, selectedImage: self.$imagePicked, source: .camera).edgesIgnoringSafeArea(.all)
}
}
}
}
当然,你的头像视图会有所有必要的代码来更新这些绑定。就像这样
HStack () {
Button(action: {
self.showActionSheet.toggle()
}) {
MyImageView(image: self.imagePicked)
}
.actionSheet(isPresented: $showActionSheet, content: {
ActionSheet(title: Text("Picture source"), buttons: [
.default(Text("Camera"), action: {
self.pickerSource = .camera
self.showImagePicker.toggle()
}),
.default(Text("Photo Library"), action: {
self.pickerSource = .photoLibrary
self.showImagePicker.toggle()
}),
.destructive(Text("Cancel"))
])
})
}
说实话,我很犹豫是否要提供这个解决方案,这段代码让我的眼睛流血,但我想有人在读到这篇文章时可能会有更好的想法,并提供一个真正干净的SwiftUI方式。
这个解决方案的好处是它能很好地管理方向的变化,让我们面对现实吧,UIImagePickerController并不能很好地适应一个工作表。对于照片库来说,它很好,但对于相机来说就不行了。