SwiftUI 全屏 UIImagePickerController(相机)
Posted
技术标签:
【中文标题】SwiftUI 全屏 UIImagePickerController(相机)【英文标题】:SwiftUI Full-Screen UIImagePickerController (Camera) 【发布时间】:2020-04-22 21:54:49 【问题描述】:我通过在sheet
修饰符中使用逻辑来在我的应用程序中呈现UIImagePickerController
。简而言之,以下三种类型处理在 UIViewControllerRepresentable
类型内显示和关闭 UIImagePickerController
的实例,这可以按预期工作:
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 应用程序中,您可以通过设置所呈现视图的modalPresentationStyle
来控制它。但这不适用于sheet
。没有地方可以指定演示样式(并且尝试在UIImagePickerController
上设置它不起作用)。请参阅***.com/a/58970681/1271826 了解可能的解决方法。
只是一个友好的建议:将来如果您可以发布MCVE 可能会很有用。像PhotoSelectionView
和PhotoSource
这样的东西在这里没有定义,这使得很难表现出问题,从而推断出发生了什么。如果您共享足够的代码来重现相关问题,您将来可能会收到更多回复...
@Rob,您提供的 URL 很有帮助,因为我错过了 UIHostingController
可用于表示 SwiftUI 视图层次结构的概念。另外,我很欣赏创建 MCVE 的建议。我应该从我的原始代码示例中删除 PhotoSelectionView
和 PhotoSource
。
在 SwiftUI 中没有简单的方法来显示全屏 UIImagePicker 真是太疯狂了
【参考方案1】:
结合@LaX 和@GrandSteph 的答案,我有:
.fullScreenCover(isPresented: $activeSheet, content:
ImagePicker(image: $inputImage, sourceType: .camera)
.edgesIgnoringSafeArea(.all)
)
【讨论】:
【参考方案2】:在 ios 14 中,Apple 添加了 fullScreenCover(ispresented:ondismiss:content:)
和 fullScreenCover(item:ondismiss:content:)
方法,它们完全符合您的要求。
从你的例子:
var body: some View
Text("Hello, World!")
.fullScreenCover(item: $activeSheet) (sheet) in self.view(for: sheet)
或者,如果您只是想展示一个视图:
@State var customViewIsShown = false
// ...
var body: some View
Text("Hello, World!")
.fullScreenCover(isPresented: $customViewIsShown)
YourCustomView(isShown: $customViewIsShown)
【讨论】:
【参考方案3】:好的,对这个答案持保留态度。因此,我可能会因为这个以及我所有的程序员孩子和我一起被投下地狱……但 Apple 也应该如此,因为它没有提供一种在 SwiftUI 中呈现全屏 UIImagePickerController 的简单方法。
非常糟糕的诀窍是在 rootView 中创建您的选择器并让它忽略安全区域。然后将所有必要的参数作为绑定传递给需要 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)
当然,您的 Avatar 视图将包含更新这些绑定所需的所有代码。像这样的
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 不适合工作表。照片库可以,相机不行。
【讨论】:
以上是关于SwiftUI 全屏 UIImagePickerController(相机)的主要内容,如果未能解决你的问题,请参考以下文章
如何在 SwiftUI 中呈现全屏 AVPlayerViewController